Search analytics & privacy
Search analytics & privacy
Navvo keeps a small record of each search so it can find what's broken: queries that return nothing, results nobody opens, slow responses. Then it can fix ranking for everyone. This page sets out exactly what is recorded, what never is, how long it is kept, and how you and your users stay in control. It covers GET /search and POST /search/events.
The model in one table
| Without consent (the default) | With the user's consent | |
|---|---|---|
| Search record | Kept, not linked to a session | Kept, linked to a day-scoped session hash |
X-Navvo-Session header | Don't send it | Send a random id per session |
| Click and conversion events | Rejected | Accepted |
Browser sends Sec-GPC: 1 or DNT: 1 | No change | Treated as no consent |
analytics=false or X-Navvo-Analytics: off | Nothing kept in search analytics | Nothing kept in search analytics |
What Navvo records for each search
One record per GET /search request:
| What | Details |
|---|---|
| The query | After scrubbing, at most 200 characters, plus a normalised form used to group identical searches. |
| How it was read | The detected language, the locale, and the parsed intent: category slugs, "near me", "open now", a recognised area, a qualifier. Never coordinates or free text. |
| Where it came from | The traffic type (api, sdk, or one of Navvo's own apps). For API-key requests, the key id and project, so the record can be attributed to your project. |
| Filters and paging | Whether an origin or bbox was sent, the origin type, category, page, limit, mode, and an allow-listed summary of filters (openNow, minRating, the number of amenities, sort, radiusKm). |
| A coarse area | Only when an origin was sent: a grid cell of roughly 30 × 20 km around it, never the coordinates. It is not kept for sensitive searches. |
| The results | The total, the number shown, whether the search returned nothing, and the ids of the first 20 places returned. |
| How it was served | Keyword or meaning-based matching, any spelling variants tried, any editorial rules applied, the test group if a ranking test was running, and the response time. |
| A network hash | A keyed hash of the client's IP address computed together with the date, so hashes from different days can't be linked to each other. Navvo uses it to limit how much it records from one network and to group a burst of keystrokes. It is not kept for sensitive searches. |
| A session hash | Only with consent: a keyed hash of your X-Navvo-Session id and the date, so it can't be linked across days either. |
| What happened next | Filled in later from events: whether a result was opened, the position of the first click, and whether it led to a conversion. |
Never in a search record: the IP address itself, the user's account or user id, the user agent, exact coordinates, or the raw session id. Separately, API usage metering records the address each API-key call comes from (usually your server; your user's device when a key is used from a browser or an app) for billing and abuse prevention, whatever the analytics setting.
To protect storage, Navvo records at most 30 searches per minute from one network. Beyond that, searches are counted but not stored. Searches fired from the developer portal's Sandbox tab are never recorded.
Scrubbing
Before anything is stored, the query passes through a scrubber. Arabic-Indic and full-width digits (٠٧٩…, 079…) are converted to ASCII first, so numbers can't slip past in any script. Then:
| Found in the query | Stored as |
|---|---|
| Email addresses | [email] |
| Web addresses | [url] |
Social handles (@name) | [handle] |
Phone numbers, including spaced, dashed, dotted and comma-separated forms (the Arabic comma ، too) and +962 numbers, and any run of 6 or more digits | # |
| Card-like numbers of 13–19 digits | # |
| Bank account numbers (IBAN) | [iban] |
Vehicle plate numbers such as 12-34567 | # |
Coordinates typed as a pair, such as 31.9539, 35.9106, and Plus Codes | # |
The placeholders replace the value both in the stored text and in the normalised form used to group identical searches. A query that needed scrubbing is never used for suggestions or ranking signals.
Sensitive searches
When the query or its top result falls in a sensitive category, Navvo keeps the search record without anything that could link it. The sensitive categories are health (hospitals, clinics, pharmacies and similar) and religion (places of worship). The record has no session hash, no network hash and no area cell, and events for the search are rejected. These searches are never used for ranking signals or suggestions.
Consent and sessions
Ask first
Send X-Navvo-Session only after the user has opted in, for example through a setting such as "Improve search with my activity" that is off by default. That is how navvo.io does it. Without the header, the search works exactly the same, and its record is not linked to any session.
Generate the id
// 16 random bytes -> 22 URL-safe characters, created fresh for each session.
function newSearchSession() {
let id;
do {
const bytes = crypto.getRandomValues(new Uint8Array(16));
id = btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
} while (/\d{6}/.test(id)); // Navvo ignores ids with 6+ digits in a row (they look like phone numbers)
return id;
}
- Format: 16–64 characters from
A–Z a–z 0–9 _ -, with no run of six or more digits. Navvo ignores any other value, and the search is treated as unconsented. - Lifetime: create a new id per session, meaning per browser tab (
sessionStorage) or per app launch. Don't keep one across days: Navvo's hash includes the date anyway, so a long-lived id adds nothing. - Never identifying: don't derive it from a user id, email address, phone number, device identifier or advertising identifier.
- Withdrawal: when the user turns the setting off, stop sending the header and events at once, and discard the id.
Privacy signals
If the user's browser sends Sec-GPC: 1 (Global Privacy Control) or DNT: 1, Navvo treats the search as unconsented even when a session id is present. If your server calls Navvo on the user's behalf, forward those two headers, or don't send a session id for those users.
Opting out entirely
Add analytics=false, or send the header X-Navvo-Analytics: off, and search analytics keep no record of that search. Use it for:
- automated tests, monitoring probes and load tests;
- bulk or batch jobs (geocoding a spreadsheet of names, for example);
- any integration whose contract says search input must not be used for analytics.
Opting out covers search analytics only. Like every API call, the request still passes through usage metering and technical logs (see Retention).
Server-to-server integrations
If your backend calls Navvo for your users:
- The network hash is of your server's address, not your users'. Search records still hold no address itself, while usage metering records your server's address for each API-key call.
- Pass your user's consented session id in
X-Navvo-Sessionexactly as a browser would, never your own user ids. - Forward
Sec-GPCandDNTfrom the user's request. - Proxy events through the same backend with the same API key, because an event must carry the key the search used.
Retention
| Data | Kept for |
|---|---|
| Search records | 30 days, then deleted. For searches made with your API keys, your project can choose 30 days (the default), 90 days or Off in the developer portal; Off also deletes what is already stored, events included. |
| Click and conversion events | 90 days |
| Daily totals: counts per day, traffic type and language, with no query text | About 13 months |
| Events whose search record never arrived | Deleted after about 24 hours |
| Technical logs | 30 days for the application's logs; the monthly archives of web-server access logs until about 30 days after the end of the month they cover. Kept for security and troubleshooting |
Technical logs are separate from search analytics, and opting out doesn't change them. The API's own request logs for search and geocoding requests leave out the query string (the search text and any coordinates), the page the request came from, forwarded client-IP headers and the country header added at the network edge, and they redact X-Navvo-Session. Web-server access logs still record each request as it was received, including the full URL and the IP address it came from, and are rotated automatically.
How the data is used
- Measuring search: the zero-result rate, click-through rate, average click position, conversion rate and response times.
- Fixing search: Navvo staff review aggregated reports, such as top queries, queries with no results and queries where nobody opens anything, and respond by adding synonyms, alternative place names and editorial rules. Query text is visible to Navvo administrators in Navvo's search console, and the text of searches made with API keys only to Navvo's highest admin role. Opening a query's detail view and exporting are audit-logged. A project's owner sees that project's own analytics, including the text of its top queries and queries with no results, in the developer portal.
- Ranking signals: aggregated clicks from Navvo's own apps (never API-key traffic) may help rank navigational queries, but only while Navvo has click-based re-ranking switched on, and only for a query seen from at least 10 distinct daily network hashes on at least 3 different days. Because the network hash includes the date, that threshold counts network-days, not different people or networks. Clicks from sensitive searches or on promoted results are never used.
- Ranking tests: while Navvo tests a ranking change, a search with a session id may be placed in a test group, and it stays in the same group for the day. Searches without a session id always get the standard ranking.
- Suggestions come from Navvo's own vocabulary (category, place and area names in Arabic, English and Arabizi) and from search phrases the Navvo team has reviewed and approved; an approved phrase may first have been noticed in people's searches. Suggestions are never generated automatically from what people type. See
GET /search/suggestions. - Your project's search traffic is not shared with other customers.
How the metrics are defined
| Metric | Definition |
|---|---|
| Searches | Search records, not counting the intermediate keystrokes of a typing burst. |
| Zero-result rate | Searches that returned nothing, divided by all searches. |
| Click-through rate | Searches with at least one valid click, divided by event-eligible searches that returned results. |
| Average click position | The mean position of the first click. |
| Conversion rate | Searches followed by a conversion, divided by event-eligible searches that returned results. |
Navvo reports a metric only when it has at least 30 searches behind it.
Treat the counts as a close estimate, not an audit log. Recording never slows a search down or blocks one: Navvo limits how much it records from one address (for searches made with an API key, per key), and it pauses recording altogether while the platform is short of storage space. Searches are still answered during a pause, the searches made in it are not added later, and the pause is announced in the changelog.
Checklist for your privacy notice
If your app uses Navvo search, your privacy notice should cover:
- that search queries are sent to Navvo to find places;
- that Navvo keeps a scrubbed, pseudonymous record of each search for 30 days to improve search, or for 90 days if you choose that for your project (then say 90 days), and daily totals without query text for about 13 months;
- if your app calls Navvo directly from the user's browser or device: that Navvo receives the device's IP address with each request and records it for billing and abuse prevention, and in technical logs kept for a limited period;
- if you offer the setting: that users who opt in let a random, per-session id link their searches to the results they open, and that those events are kept for 90 days;
- how users opt out (your setting), and that browser privacy signals (GPC and Do Not Track) are honoured.
Navvo's own policy is at navvo.io/privacy.