A user agent string may be personal data depending on how it is processed. Aggregate statistics of user agent strings are not personal data. But if you combine user agent records with IP addresses or other identifiers, the user agent string would relate to a data subject that you can single out/identify.
While user agent strings can contain arbitrary text (someone could override their user agent to put their name, street address, and tax ID there), this does not seem to be particularly relevant. For GDPR compliance, it matters more how you process the data.
While GDPR is a foundational data privacy law in the EU, the ePrivacy directive goes into more detail for internet and telecommunication services. A user agent string would usually fall under it's definition of “traffic data” because it's generally transmitted as a HTTP header. Per ePrivacy Art 6, traffic data can only be processed:
- for transmitting a communication, e.g. to have your web server respond with different content depending on mobile or desktop user agents;
- when the data is made anonymous, e.g. as part of aggregate statistics on browser versions;
- for billing purposes;
- or when the user consents, where “consent” is defined by the GDPR.
However, the ePrivacy directive is not immediately applicable law, and every EU member state has its own law implementing this directive. Thus, you should look at the laws in the country in which you reside. These laws do not override GDPR but augment it, so you still have to ensure GDPR compliance (such as having a legal basis per GDPR Art 6 for every processing of such data).
I think that recording {url, date, user agent} tuples for the purpose of building statistics is not personal data in your context, or is at least a processing of personal data that doesn't require identification per GDPR Art 11. Such records would likely count as “anonymous” in the sense of ePrivacy, so that you can collect such statistics without having to ask for consent.
However, if a user agent is rare relative to the traffic volume on your site, it would still be possible to single out a particular user. Thus, it could make sense to break the connections between date and user agent or to never store individual records, just aggregate data. Speaking as a software developer, reasonable solutions might include:
- using streaming Bloom filters to avoid storing unique records, or using other privacy-preserving probabilistic data structures
- only storing denormalized records, and truncating/rounding timestamps to avoid linking events via their time. Instead of one table with a {url, timestamp, user agent} per event you might have separate tables with {url, time slot, counter} and {user agent, time slot, counter} aggregate records were the time slots are appropriately spaced for the traffic of the site.