Hazely Privacy Policy
About this version. Version 3.0 replaces version 2.1 in full. Version 2.1 described a server architecture Hazely no longer runs and, in several places, described data handling that did not match the app. Every statement in this version was checked against the shipping code and the deployed backend on 4 August 2026. Where the app does something we would rather it did not, this policy says so.
Language. This policy is published in English at hazely.nl/privacy and in Dutch at hazely.nl/privacybeleid, at the same version number and the same effective date. Neither language version is designated as prevailing over the other: they are maintained together and are meant to say the same thing. If you find a difference between them, tell us at privacy@hazely.nl — we will correct it and republish both. The app itself is available in English and Dutch.
1. Who we are (controller)
For the purposes of the EU General Data Protection Regulation 2016/679 (GDPR) and the Dutch Uitvoeringswet AVG (UAVG), the controller of the personal data described in this policy is:
Ali Khoshraftarmonfared, a natural person established in the Netherlands, trading as Tesseractive — the developer name published on the Google Play listing for nl.hazely.app.
Hazely is not run by a company. There is no BV, no other legal entity and no Chamber of Commerce (KvK) registration behind it yet, so this section gives you no KvK number, no VAT number and no company legal form: there are none to give, and we are not going to invent one. A Dutch business registration is being arranged. When it exists, this section will be updated and this policy reissued under a new version number.
Postal address. We do not publish one, because the only address that exists today is a private home address. You can still have it: ask at privacy@hazely.nl and we will send it to you in writing. That is also the address to use if you need to serve something formally.
We are established in the Netherlands, so no representative under Art. 27 GDPR is required.
| Contact channel | Address |
|---|---|
| Privacy and data-protection questions | privacy@hazely.nl |
| Data subject rights requests | privacy@hazely.nl — see hazely.nl/data-request for what to include |
| Data-protection contact | dpo@hazely.nl — see the note below |
| Legal | legal@hazely.nl |
| Security incidents and vulnerability reports | security@hazely.nl |
| Illegal content and abuse reports | abuse@hazely.nl |
| Postal address | on request, from privacy@hazely.nl |
About dpo@hazely.nl. We have not designated a Data Protection Officer, and we are not required to under Art. 37(1) GDPR: we are not a public authority, and Hazely does not operate at the scale that provision contemplates. dpo@hazely.nl reaches the same person as privacy@hazely.nl. It is published because earlier versions of this policy published it and it still appears in the app and on our website. Treat it as a routing alias for privacy correspondence, not as the designation of a data protection officer under Arts. 37–39 GDPR. If that ever changes, we will say so here and notify the Autoriteit Persoonsgegevens as Art. 37(7) requires.
2. Scope and definitions
This policy covers the personal data we process when you install, open, or use the Hazely mobile app — nl.hazely.app on Android and nl.hazely.ios on iOS — and when you visit hazely.nl.
- "You" means the person using the App or the website.
- "We" means the controller named in §1.
- "the App" means both the Android and the iOS app. Where the two behave differently, we say so.
Hazely is an information-only app. It shows publicly listed licensed coffeeshops, their opening hours, ratings and house rules, gives walking directions, extracts text from a photo of a printed menu, and shows a reference catalogue of cannabis strains. It sells nothing, takes no orders, processes no payments, and has no user accounts.
This policy does not cover coffeeshops, third-party websites, or any other service you reach from a link in the App. Read their own privacy notices.
Two companion documents form part of this notice:
- The Cookie & Tracker Policy explains what is stored on or read from your device, and the consent required for that under Art. 11.7a Telecommunicatiewet and Art. 5(3) of the ePrivacy Directive 2002/58/EC.
- The Notice and Action procedure, available in the App, explains how to report illegal content. You can also write to abuse@hazely.nl.
This policy is also the privacy policy referenced in Hazely's Google Play Data safety section and in the App Store privacy label. Those two disclosures must say the same things this policy says. If you spot a difference, tell us at privacy@hazely.nl.
3. What data we process
3.1 Data you give us directly
| Data | When | What we do with it | Where it goes |
|---|---|---|---|
| Age confirmation (a yes/no flag plus a timestamp) | First launch | Records that you confirmed you are 21 or older | Your device only. Android: app preferences, excluded from Google Backup. iOS: UserDefaults, which is included in your iCloud backup by default |
| Acceptance of the Terms, this policy and the Cookie Policy | First launch, and after a change to the documents that gate the App | Evidence that you were asked and answered | Your device only. Android stores the exact version string you accepted; iOS currently stores only that you accepted, not which version |
| Your consent choices (analytics, crash reporting, personalised ads) | First launch and whenever you change them in Settings | Controls what optional processing runs | Your device only |
| Text you type into the map search bar | As you search | Filters the visible shop list on your device. The text itself never leaves your device. If you have Analytics on, we send how many characters you typed and how many results came back — not what you typed | Your device. Only the length and the result count reach Google, and only if Analytics is on |
| Text you type into the strain catalogue search | When you search for a strain we do not already have | This one is sent. It goes to our server, and on to Google's Gemini API, so an entry can be generated. If Analytics is on, we separately record only the length of what you typed, not the text | Our server (Google Cloud, Belgium); Google Gemini; and the text appears in our server request logs |
| Photographs of coffeeshop menu boards | When you tap "Scan Menu" and confirm | AI text extraction — see §3.3 | Our server, then Google Gemini. The image itself is never stored |
| Owner verification / correction requests (shop name, contact name, business email, optional phone, message) | When you submit the owner form | Checking and correcting public listing information | Stored in our database (Firestore, Belgium) |
| Illegal-content and abuse reports (message, and an email address if you choose to give one) | When you submit a report | Handling the report | Stored in our database (Firestore, Belgium) |
| Favourites (the IDs of shops you starred) | When you tap the star | Shows your favourites | Your device only — the list is never transmitted. But if Analytics is on, the act of favouriting sends a shop_favorited event with the shop ID to Google |
We do not operate a feedback form, and there is no crash-reporter comment box. Version 2.1 said we did. That was wrong and has been removed.
3.2 Data collected automatically
Most of the rows below are off unless you switch them on. Firebase Analytics, Crashlytics and Performance Monitoring all ship disabled in the app manifest and stay disabled until you consent. A few rows run regardless of your choices; those are marked.
| Data | Purpose | Who receives it | Runs when |
|---|---|---|---|
| Foreground device location (precise or approximate, whichever you granted) | Centre the map, draw your location dot, measure walking distance | Not sent to Hazely's servers. Used on your device | Only while the App is open and only if you grant the OS permission. We do not ask for background location |
| Walking route request — your starting coordinates and the destination coordinates | Produce the walking route you asked for | Mapbox Inc. (United States). The coordinates travel in the request URL | Only when you tap "Navigate" |
| Mapbox Maps SDK telemetry — device location and map-usage data collected by Mapbox's own SDK | Mapbox's own map-improvement purposes | Mapbox Inc. | Android: only if you turned Analytics on. The App switches Mapbox telemetry off otherwise, and does so again from the stored setting each time the map is built. iOS: the App does not switch it off — use Mapbox's own opt-out in the map's attribution control. See §10 |
| Mapbox monthly-active-user "turnstile" event | Mapbox's licence metering | Mapbox Inc. | Whenever the map is on screen, even with Mapbox telemetry switched off. The SDK offers no way to suppress this one |
| Map tile and style requests | Draw the map | Mapbox Inc. (your IP address and the area you are looking at) | Whenever the map is on screen |
| On-device proximity check | Every time your location updates, the App measures the distance to the nearest coffeeshop. Within 50 metres it holds that shop's name in memory so it can show the "you arrived" card and suggest nearby food | Nobody. This never leaves your device | Whenever location is granted and the App is open |
| Crash reports — stack trace, crash dump, device model, OS version, app version, and a per-installation identifier generated by Google | Fixing crashes | Google (Firebase Crashlytics) | Only if you turn crash reporting on |
| Selected-shop crash keys (Android) — the ID and name of the shop you last opened are attached to any crash report | Reproducing crashes | Google (Firebase Crashlytics) | Only if you turn crash reporting on |
| Crash titles opened as tracker issues — crash title, subtitle, app ID and app version | Our own bug tracking | GitHub, Inc. (United States) | When Crashlytics raises a new-crash or regression alert. No crash means no issue |
| App-usage events — see the full list below | Understanding which features are used | Google (Google Analytics for Firebase) | Only if you turn Analytics on |
| Advertising ID (Android) | Collected by the Analytics SDK by Google's default | Only if you turn Analytics on. Note: this rides the Analytics switch, not the personalised-ads switch. There is currently no separate control for it. From Android 1.0.7 onward, collection of the Advertising ID is switched off entirely | |
| Performance traces — app start time, screen rendering, and automatic traces of the App's own network requests (host and path, payload sizes, response codes) | Finding slow screens and slow requests | Google (Firebase Performance Monitoring) | Controlled by the Analytics switch. There is no separate control |
| Remote configuration fetch — a Firebase installation identifier, app version, platform, language and country | Feature flags, and the "update required" kill switch | Google (Firebase Remote Config) | On both platforms, only after you have answered the consent screen — whatever you answered. Nothing is fetched before that |
| App and device attestation token (Android) — Google Play Integrity via Firebase App Check | Stopping abuse of our API by fake clients | On API requests once you have answered the consent screen — including if you rejected everything optional | |
| Play in-app update check (Android) | Telling you when a new version is required | Google Play | At launch and on resume, before the age gate |
| IP address | Delivering the response; rate limiting; abuse prevention | Google (Cloud Functions, Cloud Logging, Firebase Hosting) | Every request to our server. Your full IP address is received and logged. It is not truncated. Version 2.1 claimed truncation to /24 and /48; that described a server we no longer run |
Client headers X-Hazely-Client, X-Hazely-App-Id | Telling Android and iOS traffic apart | Google (server logs) | Every API request. These identify the platform, not you |
| Store review prompt counters | Deciding when to show the "rate this app" prompt | Nobody — device only. The prompt itself is shown by Google Play / Apple | Device only |
| Advertising | — | Nobody today | The AdMob SDK is built into the Android app, but every ad placement is switched off and no ad is requested. See §4.3 |
The exact analytics events. If — and only if — you turn Analytics on, the Android app can send these events to Google. Each is tied to a Firebase app-instance identifier: a pseudonymous per-installation ID that Google can link across your sessions.
| Event | What it carries |
|---|---|
screen_viewed | which screen |
age_gate_confirmed | nothing |
consent_recorded | your three consent choices |
settings_opened, owner_portal_opened | nothing |
shop_detail_opened | shop ID and shop name |
navigate_tapped | shop ID and shop name |
menu_scan_started | shop ID and shop name (sent when you tap Scan, before the disclosure and the camera) |
search_submitted | the number of characters you typed and the number of results — never the text |
nearby_food_tapped | shop name |
review_opened | shop ID and shop name |
shop_favorited | shop ID |
strain_search | source, whether a match was found, and the length of your query — not the query itself |
strain_detail_opened | strain ID and type |
ad_placement_viewed | which ad slot. Not sent today, because no ad slot is enabled |
The iOS app sends a smaller set: search_submitted (query length and result count), shop_selected (shop ID and name), strain_viewed (strain ID and strain name — the Android equivalent sends the type instead of the name), menu_scan_started (shop ID) and navigation_started (shop ID and name).
Android shortens every event parameter to 100 characters before sending it. iOS does not, which matters for none of the parameters above, since none of them carries text you typed.
A change already under way: from the next releases — Android 1.0.7 and the next iOS build — the shop-name parameter is removed from all events (the shop ID remains) and iOS's strain_viewed sends the strain ID instead of the name; everything above describes the builds currently shipping.
3.3 What happens to your menu photos
Before the camera opens, on both platforms, the App tells you that an AI reads the photo and asks you to keep faces, ID documents and vehicle plates out of the frame, and then asks you to confirm. You can cancel at that point. Nothing is captured or sent unless you confirm. Then:
- Your camera takes the photo. On Android it is written to the App's private cache, rotated, resized and re-compressed, and the temporary file is then deleted. On iOS it is compressed in memory. Re-compressing removes EXIF metadata as a side effect.
- The image is uploaded over HTTPS (maximum 8 MB) to our Cloud Function in europe-west1 (Belgium). If you scanned from a shop's page, the shop's ID is sent with it.
- Our server re-encodes the image to strip EXIF, IPTC and XMP metadata. If the image cannot be decoded, and therefore cannot be stripped, the upload is rejected — you are asked to retake the photo, and nothing is forwarded to anyone. Version 2.1 promised unconditional stripping while the server actually forwarded the original bytes on a decode failure. That is fixed and deployed; the promise is now true without qualification.
- The cleaned image is sent to Google's Gemini API at
generativelanguage.googleapis.com— the Gemini Developer API, which is a global endpoint with no EU data-residency guarantee. Version 2.1 said "EU region selected". That was wrong. Version 2.1 also named Anthropic, PBC as an alternative provider; no Anthropic service is used and that name has been removed. - We never store the image. Only the extracted text.
- The extracted result (item names, categories, warnings) is written to our database as a record with a random ID and no identifier of you. It is kept for up to 30 minutes and then deleted — see §7 for how that is enforced.
- Strain names in your photo that are not already in our catalogue are added to a shared, public strain catalogue as AI-generated entries and served to all users. These are kept indefinitely. They contain no information about you.
- For each scan our server logs the image sizes, the media type and the shop ID. That log line sits in the same log entry as your IP address.
Does Google train on your photo? We are not going to tell you it does not, because we have not established that we are entitled to say so. Google's Gemini API Additional Terms treat data use differently across service tiers and customer establishments, and which of those apply to our API key is not something the App's source code shows. Version 2.1 stated flatly that images are never used to train the model. We have removed that claim rather than repeat it unverified. If you would rather no photograph of yours reached Google at all, do not use Scan Menu: nothing is sent unless you start a scan and confirm.
3.4 What we deliberately do not collect
- Account credentials. There is no login, anywhere in the App.
- Payment information. The App processes no payments.
- Your home or work address.
- Background location. We do not request it and the App cannot track you when it is closed.
- Your contacts, your photo library, your microphone, or your calendar.
- Health, biometric or identity-document data — we never ask you for any.
- Any user ID of our own. We never call
setUserId. We do not build a cross-device profile. - Your favourites list. It stays on your device.
- Your location, on our own servers. Our shop API is called with no coordinates at all.
- What you type into the map search bar. It filters the list on your device; only its length and the number of results are ever sent, and only with Analytics on. This is not true of the strain catalogue search, which is sent — see §3.1.
Version 2.1 also claimed we collect no "record of which coffeeshop you visited". That claim was not correct when Analytics is switched on, and has been removed. See §3.5.
3.5 Cannabis, coffeeshops and special-category data
We never ask about your cannabis use, your health, or what you buy. We hold no purchase record and no visit log, and your location never reaches our servers.
But we will not tell you that no inference is possible. If you turn Analytics on, the events in §3.2 include the names of coffeeshops you open, favourite, ask directions to and photograph a menu at, and the strain pages you read — all under one per-installation identifier held by Google, kept for the analytics retention period. Photographing a menu board in particular can normally only happen while you are physically at that shop.
EU case law applies a broad test: data can fall under Art. 9(1) GDPR if it is liable to reveal a special category by inference, not only if it states one (CJEU C-184/20 OT, 1 Aug 2022; C-252/21 Meta Platforms, 4 Jul 2023; C-21/23 Lindenapotheke, 4 Oct 2024). Whether interest in a coffeeshop is "data concerning health" under Art. 4(15) GDPR has not been decided by any court or regulator. We are not going to claim the answer is obviously no, and we are not going to claim it is obviously yes. What we can tell you is exactly what is sent, which is the table above.
What this means for you in practice: if you do not want that stream to exist, leave Analytics off. It is off by default and refusing it costs you nothing — every feature of the App works exactly the same. Crash reporting carries the same signal in a smaller way, through the two Crashlytics keys named in §3.2, and it is off by default too.
We have taken external advice on whether to remove the shop identifier and shop name from those events entirely. Until that is settled, the position is the one described here rather than a promise we have not implemented.
3.6 Data about people who are not Hazely users
Some data we hold is about people who never used the App. Art. 14 GDPR applies to it, and this section is that notice.
| Whose data | What | Where it came from | Why we hold it | Basis | How long |
|---|---|---|---|---|---|
| Authors of Google reviews | Reviewer display name, rating, review text, relative time | The Google Places API, refreshed by a daily job | So users can see what a shop is like before walking there | Art. 6(1)(f) — our and our users' interest in accurate, useful public listings | No retention limit is implemented today. Reviews are carried forward on every sync and are re-served until we delete them |
| People visible in shop photos | Photographs from public shop listings, served through our image proxy | Google Places | Illustrating a listing | Art. 6(1)(f) | Same as above |
| Bystanders in a menu photo | Anything else that happens to be in the frame | You, when you scan a menu | Not wanted — this is why we ask you to check the frame before the camera opens | Art. 6(1)(f), and minimisation by asking you not to capture it | The image is never stored; only extracted menu text is kept, for up to 30 minutes |
Two things we would rather be able to write differently, stated as they are:
- There is no automatic deletion for the cached reviews and photos. We have not set a period and we are not going to publish one we do not enforce. We delete on request, and we delete a shop's cached content when we stop listing the shop.
- We give this notice publicly rather than individually. We hold no contact details for review authors — the Places API gives us a display name, not an address — so there is no one to write to. We are not asserting here that Art. 14(5)(b) GDPR (disproportionate effort) applies; that assessment has not been completed. We are telling you what we hold and how to get it removed.
If you are a review author or appear in a photo and want that removed, email privacy@hazely.nl. We will remove it from our cache. We cannot remove it from Google.
4. Purposes, lawful bases, recipients and retention
4.1 The full table
Consent-based rows are marked Consent. Where the operation also stores information on, or reads information from, your device, Art. 11.7a Telecommunicatiewet requires that consent separately from the GDPR — that is noted as (+ Tw 11.7a).
| Purpose | Data used | Lawful basis | Recipients | Retention |
|---|---|---|---|---|
| Confirm you are 21+ | Age flag, timestamp | Art. 6(1)(f) — legitimate interest in keeping a cannabis-related app away from minors, and in meeting Google Play and Apple age requirements | Nobody | Until you uninstall or reset |
| Record what you accepted and what you consented to | Terms version, consent version, three consent booleans | Art. 6(1)(f) — legitimate interest in being able to demonstrate consent, as Art. 7(1) GDPR requires | Nobody | Until you uninstall or reset |
| Show the map, shop list, opening hours and ratings | Your request, your IP address | Art. 6(1)(f) — providing the service you opened the App to use | Google (hosting, logs); Mapbox (tiles) | Logs: see §7 |
| Show your position and measure distance | Foreground location | Art. 6(1)(f), plus your OS-level permission | Nobody (stays on the device) | Discarded when the App closes |
| Detect that you are within 50 m of a coffeeshop | Foreground location, shop coordinates | Art. 6(1)(f) — showing the arrival card and nearby-food suggestions you asked for | Nobody | Held in memory only |
| Give walking directions | Start and destination coordinates | Art. 6(1)(f) — you asked for the route | Mapbox Inc. (US) | Governed by Mapbox |
| Mapbox Maps SDK telemetry | Device location and map-usage data | Art. 6(1)(a) Consent (+ Tw 11.7a) on Android, where it rides the Analytics switch. On iOS the App does not gate it, and you opt out through Mapbox's own control | Mapbox Inc. (US) | Governed by Mapbox |
| Extract text from a menu photo | The photo; optional shop ID; your IP | Art. 6(1)(a) Consent — you start the scan and confirm the notice | Google (Cloud Functions, Gemini) | Image: never stored. Result: see §7 |
| Build strain catalogue entries we do not have | The strain name you typed | Art. 6(1)(a) Consent for sending your query; Art. 6(1)(f) for maintaining the catalogue | Google (Cloud Functions, Gemini); the entry is then public | Query appears in server logs; the generated entry is kept indefinitely |
| Product analytics | The events in §3.2, app-instance ID, Advertising ID (Android) | Art. 6(1)(a) Consent (+ Tw 11.7a) | Google — Analytics for Firebase | See §7 |
| Crash reporting | Stack traces, device and app details, installation ID, selected-shop keys | Art. 6(1)(a) Consent (+ Tw 11.7a) | Google — Crashlytics; crash titles to GitHub, Inc. | 90 days at Google; GitHub issues until we delete them |
| Performance monitoring | App start, screen rendering, network request traces, installation ID, IP | Art. 6(1)(a) Consent (+ Tw 11.7a) — but controlled by the Analytics switch, with no separate control | Google — Performance Monitoring | See §7 |
| Feature flags and the "update required" kill switch | Firebase installation ID, app version, platform, language, country | Art. 6(1)(f) — keeping the App working and being able to disable a broken or unsafe build. For the device read/write we rely on the "strictly necessary" exemption in Art. 11.7a(3)(b) Tw | Google — Remote Config | Governed by Google |
| Anti-abuse attestation of the app and device | Play Integrity / App Check token | Art. 6(1)(f) — security. Device read relies on Art. 11.7a(3)(b) Tw | Google — App Check, Play Integrity | Governed by Google |
| Rate limiting and abuse prevention | Full IP address as the rate-limit key | Art. 6(1)(f) — Recital 49 GDPR | Held in our function's memory | For the life of the server instance |
| Server request logs | Full IP, request URL (which includes strain search text), user agent | Art. 6(1)(f) — operating and securing the service | Google — Cloud Logging, Firebase Hosting | See §7 |
| Owner verification and correction requests | Shop name, contact name, email, optional phone, message | Art. 6(1)(f) — accurate public listings; Art. 6(1)(b) where you are asking us to act on your request | Google (Firestore); our mail provider if you write to us | See §7 |
| Illegal-content and abuse reports | Message, optional email | Art. 6(1)(f) — safety and abuse handling; Art. 6(1)(c) to the extent a notice-and-action duty applies to us in law | Google (Firestore); our mail provider | See §7 |
| Keeping shop listings accurate | Public listing data from Google Places and OpenStreetMap, including reviewer names and review text | Art. 6(1)(f) — see §3.6 | Google (Places, Firestore) | See §3.6 |
| Asking you to rate the App | On-device counters | Art. 6(1)(f) | Google Play / Apple show the prompt | Device only |
| Advertising | Advertising ID, TCF consent string | Art. 6(1)(a) Consent (+ Tw 11.7a) | Google AdMob | Not applicable — no advertising runs today. See §4.3 |
Where we rely on legitimate interests (Art. 6(1)(f)), the interests are: giving you a working map and directions; keeping public listings accurate; keeping the service secure and available; being able to demonstrate the consent you gave; and keeping minors out of a cannabis-related app. You can object to any of it under Art. 21 GDPR — see §9.
Two bases that changed since version 2.1, and why it matters to you. Version 2.1 gave Art. 6(1)(c) (legal obligation) for the age gate and the acceptance log. Art. 6(3) GDPR requires such an obligation to be laid down in Union or Member State law, and there is none here: the Opiumwet tolerance criteria bind the coffeeshop rather than an information app, and the age there is 18, while our 21+ rule comes from app-store policy. We now rely on Art. 6(1)(f) instead. The practical difference is in your favour: Art. 6(1)(c) processing carries no right to object, and Art. 6(1)(f) processing does.
On Remote Config and App Check. Neither runs before you have answered the consent screen, on either platform — that is a hard gate in the code, not a convention, and it holds whatever you answered, because the "update required" kill switch has to keep working for someone who declined everything optional. For the on-device storage those two use after that point, we rely on the strictly-necessary exemption in Art. 11.7a(3)(b) Tw. That assessment is our own and has not been confirmed by an external adviser or by a regulator; we say so rather than present it as settled.
4.2 Do you have to give us this data? (Art. 13(2)(e) GDPR)
| Data | Do you have to? | If you decline |
|---|---|---|
| Age confirmation | Yes, to use the App | On Android the App stops there. There is no other way in |
| Accepting the Terms and this policy | Yes, to use the App | The App does not proceed |
| Consent to analytics, crash reporting, ads | No — all three are optional | Everything in the App works exactly the same. This is the default |
| Location permission | No | The map works. You lose the location dot, walking distance and navigation |
| Camera | No | You cannot use Scan Menu. Nothing else changes |
| Owner form / report form fields | Only if you choose to submit one | The form cannot be submitted without the required fields |
Nothing here is a statutory or contractual requirement to provide data, except that we cannot lawfully or practically operate the App for someone who will not confirm they are 21+.
4.3 Advertising and partner links, as they actually stand today
No advertising runs in Hazely. The Android app contains the Google Mobile Ads (AdMob) SDK and Google's certified consent management platform (UMP), but every one of the six ad placements is switched off, both in the app's built-in defaults and in the published server configuration. No ad is requested, no ad consent form is ever shown, the ads SDK is never started, and no ad has ever been served. The iOS app has no ads SDK at all.
No affiliate or partner monetisation runs either. The "food nearby" card that can appear when you arrive at a shop carries no partner link today: the feature is switched off and the partner URL is empty. We are not in any affiliate programme, and we receive no commission from anything in the App.
Not currently applicable. If advertising is ever switched on, Google's consent form will be shown before any personalised ad is served, non-personalised ads will be used if you refuse, and this policy will be updated before that happens rather than after. You should also know that for advertising Google positions itself as an independent controller, not as our processor, so it would process that data for its own purposes under its own privacy policy. Version 2.1 described AdMob as a processor under Art. 28 GDPR. That was wrong. None of this paragraph describes anything happening today.
5. Recipients — who else handles your data
| Recipient | What they do for us | Role | Where |
|---|---|---|---|
| Google — Cloud Functions & Firestore | Runs our backend and database | Processor | europe-west1 / eur3 — in the EU |
| Google — Firebase Hosting | Serves hazely.nl and our API edge | Processor | Global edge; logs at Google |
| Google — Gemini Developer API | AI text extraction from menu photos; generating strain entries | Processor | Global endpoint |
| Google — Analytics for Firebase | Product analytics (only with your consent) | Processor, under Google's separate Analytics/Measurement terms rather than the general Firebase terms | Global Google infrastructure |
| Google — Crashlytics | Crash reports (only with your consent) | Processor | Global |
| Google — Performance Monitoring | Performance traces (only with your consent) | Processor | Global |
| Google — Remote Config, Installations, App Check / Play Integrity | Feature flags, kill switch, anti-abuse attestation | Processor | Global |
| Google — Cloud Logging | Server request logs | Processor | Google infrastructure |
| Google — Places API | Public shop listing data, ratings, reviews, photos | Processor for the enrichment; the data itself is Google's | Server-to-server — your IP is never exposed to Google Places by the App |
| Microsoft — Exchange Online (Microsoft 365) | Receives and stores everything you email to privacy@, dpo@, legal@, security@ and abuse@hazely.nl, including the contents of rights requests and abuse reports. The hazely.nl mail exchanger points at Microsoft's mail service | Processor | Microsoft mail infrastructure |
| Google Play / Apple | The in-app "rate this app" prompt, and on Android the in-app update check | Independent controllers for their own store data | — |
| Google AdMob and Google UMP | Advertising — not active; nothing is sent | Independent controller for ad data, not our processor | — |
| Mapbox Inc. | Map tiles and styles, walking directions, and the Maps SDK's own telemetry | Processor for tiles and routing; its role for SDK telemetry is not settled and we have not determined it | United States |
| GitHub, Inc. (Microsoft) | Receives crash titles as issues in our private bug tracker | Processor | United States |
Removed in this version: Anthropic, PBC and Hetzner Online GmbH / the current VPS provider were both named as processors in version 2.1. Neither receives any data. There is no Anthropic call anywhere in our systems, and we no longer run a VPS. GoDaddy was listed as our domain registrar; a registrar does not process your personal data and has been removed.
On processing agreements. Version 2.1 stated that every processor is "contractually bound by a Data Processing Agreement under Art. 28 GDPR". We do not repeat that, because we have not verified it for every recipient in the table above, and stating it would be easier than checking it. Where a recipient is not a processor at all we now say so — AdMob is an independent controller for ad data, and Google Play and Apple are independent controllers for their store data. We are working through the remainder; when it is settled this section will say which terms cover which recipient, per recipient, rather than in one sentence.
We do not sell your data to anyone, ever.
6. International transfers (GDPR Chapter V)
Some of the recipients above process data outside the European Economic Area. Being accurate about which ones matters, and version 2.1 was not.
| Where the data actually is | Which services |
|---|---|
| Inside the EU | Cloud Functions and Firestore (europe-west1 in Belgium, eur3 multi-region). This is where menu-scan results, owner requests and reports live |
| Global Google infrastructure — transfers outside the EEA occur | Analytics for Firebase, Crashlytics, Performance Monitoring, Remote Config, Installations, App Check, Cloud Logging, and the Gemini Developer API endpoint |
| United States | Mapbox Inc.; GitHub, Inc. |
| Microsoft mail infrastructure | Email sent to our published addresses |
Version 2.1 said Firebase Analytics and Crashlytics were processed in "EU (Frankfurt region)" and that Gemini ran in "an EU region selected". Neither is correct. Google's own documentation (Privacy and Security in Firebase, page last updated 18 February 2026) states that most Firebase services run on global Google infrastructure with no data-location choice, and the Gemini Developer API endpoint we call offers no regional selection.
For transfers outside the EEA we rely on the safeguards in each provider's own terms — the Standard Contractual Clauses modules those terms incorporate, and/or the provider's certification under the Data Privacy Framework:
- the EU Standard Contractual Clauses (Commission Implementing Decision (EU) 2021/914); and
- where the recipient is certified, the EU–US Data Privacy Framework (Commission Implementing Decision (EU) 2023/1795, in force). An appeal against that decision is pending before the Court of Justice (C-703/25 P), which is why the Standard Contractual Clauses remain relevant even where a certification exists.
We say "rely on" here the way §5 says it about processing agreements: we have not independently verified, recipient by recipient, which of these instruments is actually in place for each transfer. The protections we can verify are the practical ones described in §3 and §5: an EU processing region where the provider offers one, and sending as little as possible in the first place.
Ask us at privacy@hazely.nl for a copy of the safeguards.
7. How long we keep things
| Data | Retention |
|---|---|
| Age flag, acceptance record, consent choices, favourites, theme, cached strain list, review-prompt counters | On your device until you uninstall the App or use "Reset all my privacy choices" |
| Search text you type into the map | Never leaves your device |
| Menu photo (the image) | Never stored. Held in server memory for the length of the request |
| Menu scan result (the extracted text) | Up to 30 minutes, then deleted. Two mechanisms enforce this: every record is written with an expiry timestamp and a Firestore time-to-live policy deletes it server-side whether or not anyone reads it again, and a record found to be expired is deleted and refused the moment it is read. Both are live. One caveat: a small number of records created before the expiry field existed carry no expiry timestamp and are invisible to the automatic sweeper; those are being deleted by hand, as a one-off cleanup (August 2026) |
| AI-generated strain entries derived from scans and searches | Kept indefinitely, as part of the public catalogue. They contain nothing about you |
| Owner verification / correction requests | No automatic deletion is implemented, and we are not publishing a period we do not enforce. We delete them on request, and we delete them when they are no longer needed to keep a listing accurate. Version 2.1 published 24 months; nothing implemented it |
| Illegal-content and abuse reports | Same as above |
| Email you send to our published addresses | Held in the mailbox until we delete it. We delete correspondence we no longer need to answer you or to show we answered |
| Crash reports | 90 days at Google (Firebase published retention) |
| Crash issues in our bug tracker (GitHub) | Until we close and delete them |
| Analytics events | At most 14 months — that is the longest Analytics for Firebase allows, and the shortest it offers is 2 months. The exact figure is a setting in Google's console rather than something the App controls; ask privacy@hazely.nl if you need the figure currently in force |
| Performance data | Google's published retention: 30 days for events connected to an IP address, 60 days for installation-linked and anonymised performance data |
| Firebase installation identifiers | Google deletes them within 180 days of a deletion request |
| Server request logs (including full IP addresses) | Google Cloud Logging's default retention for the standard log bucket is 30 days, and nothing in our configuration changes it |
Version 2.1 also promised an "audit log of AI API calls" kept for 90 days, "nightly database backups" kept 14 days, and irreversible deletion "within seven days" of a retention period ending. None of those controls exists. They have been removed rather than restated.
8. Automated decisions, profiling and AI features
8.1 Automated decision-making (Art. 22 GDPR)
We make no automated decisions that produce legal effects on you or similarly significantly affect you. Nothing in the App scores, ranks, segments or profiles you. Menu scanning reads text from a photo; it does not decide anything about you.
8.2 AI transparency (Art. 50, Regulation (EU) 2024/1689 — the EU AI Act)
Article 50 of the AI Act has applied since 2 August 2026. Two features of Hazely use AI, and this is our disclosure for both. A disclosure buried in a document like this one is not enough on its own, so both of them also appear in the App.
Menu scanning. When you tap Scan Menu, an AI system — Google's Gemini — reads the text in your photograph and turns it into a list. Results can be incomplete or wrong. Do not rely on a scan for prices, availability, or anything that matters. In the App:
- Both platforms tell you before the camera opens that the scan is AI-assisted, what it extracts, and that faces, ID documents and vehicle plates should stay out of the frame, and ask you to confirm. You can cancel at that point, and nothing is captured or sent if you do.
- Both platforms repeat, with the result, that it was produced by AI and can be incomplete or wrong.
AI-generated strain entries. If you search the strain catalogue for a strain we do not have, an AI system generates an entry — name, indica/sativa type, THC and CBD ranges, effects, flavours, parentage and a one-line description — and stores it in the shared catalogue for everyone. These entries are written by AI. They are not verified by a human, and they may be wrong.
Stated plainly, because it is the weakest point in our AI transparency: those entries are shown alongside human-curated ones without a visible "AI-generated" label, and the record carries no machine-readable marker of having been AI-generated — the field for one does not exist in our data format yet. Until both are in place, treat any strain entry in Hazely as possibly AI-written, and treat this section as the notice that it may be.
Neither feature is a high-risk AI system under Annex III of the AI Act.
9. Your rights
You have the following rights. They are free to exercise, and we answer within one month (extendable by two months for complex requests, Art. 12(3) GDPR).
| Right | Article | What it means here |
|---|---|---|
| Information | 13–14 | This policy |
| Access | 15 | A copy of the personal data we hold about you |
| Rectification | 16 | Correction of anything inaccurate |
| Erasure | 17 | Deletion. Uninstalling the App erases everything held on your device, and on Android that data is not in any Google backup |
| Restriction | 18 | Pausing our processing while a dispute is resolved |
| Portability | 20 | A machine-readable copy of data you provided under consent or contract. In practice that is your consent choices and the version you accepted, both already on your device |
| Object | 21 | Stop processing based on legitimate interests (§4.1) |
| Withdraw consent | 7(3) | Any time, in Settings. Withdrawal does not undo processing that already happened |
| No automated decisions | 22 | Already the case — §8.1 |
| Complain | 77 | To the Autoriteit Persoonsgegevens, https://autoriteitpersoonsgegevens.nl/en |
How to make a request: email privacy@hazely.nl. The page at hazely.nl/data-request sets out what to include and what happens next; it is a page you can read, not a redirect.
One gap on our side, stated rather than hidden: the Android app has no in-app link to that page. The iOS app does, under Settings. On Android you reach it from hazely.nl or by emailing privacy@hazely.nl directly, which works just as well. The next Android release adds that link, together with an "App instance ID" display in Settings (with a copy button) so you can quote the identifier your analytics data is keyed to; the next iOS build adds the same ID display.
An honest limit on access, erasure and portability. We deliberately built the App without accounts and without any identifier of our own. That is good for your privacy, and it has a cost: for the analytics, crash and performance data held at Google, the records are keyed to a per-installation identifier that we cannot connect to you, and that the App does not show you. Where we genuinely cannot identify you, Art. 11(2) GDPR provides that Arts. 15–20 do not apply unless you give us information that makes identification possible.
What we can always do:
- Delete or correct an owner request or a report you submitted, using the email address you gave.
- Delete correspondence you sent to any of our published addresses.
- Confirm what categories of data exist and where — this policy.
- Tell you how to erase everything on your device: uninstall, or use Settings → Reset all my privacy choices.
And the practical answer, which is better than any of them: if you do not want analytics, crash or performance records about your installation to exist at Google, leave those switches off. They are off unless you turn them on, and uninstalling the App discards the identifier they were keyed to.
10. Turning optional processing off
| What | How |
|---|---|
| Analytics, Performance and crash reporting (Android) | App → Settings → "Analytics & Performance". Be aware: this single control currently governs analytics, performance monitoring and crash reporting together. If you consented to only one of them, the switch shows as off, and turning it on turns on all three. That is a defect in our Settings screen, not the intended design, and it is why this warning is here rather than in a release note |
| Analytics, Performance and crash reporting (iOS) | App → Settings — two independent switches: "Analytics & performance" (one switch controls both — Performance has no control of its own on iOS either) and "Crash reports" |
| Personalised ads (Android only) | App → Settings → Personalised ads. The iOS App has no advertising SDK, serves no ads, and — following App Review feedback — no longer shows an ads switch at all. No ads are served today on either platform |
| Everything at once | App → Settings → Reset all my privacy choices. This clears your choices and asks you again |
| Menu scanning | Do not tap Scan Menu, or cancel at the notice. Nothing is sent unless you confirm |
| Location | Android: Settings → Apps → Hazely → Permissions → Location. iOS: Settings → Hazely → Location. Choose "While using the app" and, if you prefer, approximate accuracy |
| Mapbox map telemetry | Android: it follows the Analytics switch above — turn Analytics off and the App switches Mapbox telemetry off too. iOS: the App does not gate it; tap the (i) / attribution control on the map and use Mapbox's own opt-out. Either way, Mapbox's monthly-active-user event still goes; the SDK gives nobody a way to stop that one |
| Everything on your device | Uninstall the App |
11. Security
What we actually do:
- Encryption in transit. TLS on every connection between the App, our backend and every processor. Plain-text traffic is disabled in the Android app.
- A closed database. Our Firestore security rules deny all direct client access. Nothing reaches the database except through our own API.
- App attestation. On Android, the App attaches a Google Play Integrity token to its requests through Firebase App Check. Server-side enforcement of those tokens is currently switched off, so today this is a defence-in-depth measure, not a guarantee that only real installations reach our API. We may switch enforcement on at any time, without notice.
- Rate limiting. The API, and the menu-scan endpoint in particular, are rate limited to prevent abuse and runaway cost.
- Managed secrets. API keys are held in Google Secret Manager and injected into the backend at runtime. They are not in our source code.
- Data separation. Public shop data is stored separately from personal submissions such as owner requests and reports.
- Menu images are never written to storage. Only extracted text is stored.
- Metadata stripping, without exception. Menu photos are re-encoded on the server to remove EXIF, IPTC and XMP metadata, and an image we cannot re-encode is rejected instead of forwarded. There is no path by which an unstripped image reaches Google.
Version 2.1 described an Nginx reverse proxy, a service bound to localhost:8080, a chmod 600 secrets file, unattended OS security updates, and truncation of IP addresses on receipt. That described a self-hosted server we no longer run. None of it applies to the current system, and the IP-truncation control does not exist in it.
No system is impenetrable. If a personal data breach occurs we will notify the Autoriteit Persoonsgegevens within 72 hours where required (Art. 33 GDPR).
How we would tell you. We have no accounts, no email address for you, and no push notifications. We therefore cannot contact affected users individually. Where a breach is likely to result in a high risk to your rights and freedoms, we will rely on Art. 34(3)(c) GDPR and make a public communication: a notice on hazely.nl and a notice inside the App. Version 2.1 promised to notify you directly. The App cannot do that.
12. Children and the 21+ age gate
Hazely is not intended for anyone under 21. On first launch we ask you to confirm you are 21 or older, and Android blocks the App if you say you are not.
This is a self-declaration. We cannot verify anyone's real age, and we do not try — verifying age would mean collecting identity documents, which would be far more intrusive than the problem it solves.
We do not knowingly process the data of anyone under 21. If you are a parent or guardian and believe someone under 21 has used the App, email privacy@hazely.nl. Almost everything the App holds is on the device itself, so uninstalling removes it immediately.
Version 2.1 described the age gate as "a technical measure under Art. 8 GDPR". That citation was wrong — Art. 8 governs a child's consent to online services below the age of 16 (set at 16 in the Netherlands by Art. 5 UAVG), which is not what a 21+ declaration is. It has been removed.
13. Changes to this policy
We will update this policy when what we do changes. The version and effective date shown with this document always identify the current text.
What re-prompts you, and what does not. The App's acceptance gate is keyed to the Terms of Use and the Cookie & Tracker Policy — the two documents you are asked to accept — and not to this Privacy Policy, which is information we owe you rather than something you agree to. Stated plainly for each platform:
- On Android, the App stores the exact version string you accepted for those two documents and asks again whenever either of them moves, including a minor revision such as 2.1 to 2.2. It used to store a whole number, so minor revisions re-prompted nobody; that is fixed.
- On iOS, the App records only that you accepted, not which version. No document change re-prompts an iOS user today. That gap is real and we are not going to describe it as anything else.
- A change to this policy does not by itself produce a new prompt on either platform.
Where a change here is material we publish it at hazely.nl/privacy and hazely.nl/privacybeleid and note it in the App's release notes.
Earlier versions. We do not publish an archive page. Ask privacy@hazely.nl for the text of any earlier version and we will send it to you. Version 2.1 promised an archive at hazely.nl/privacy/archive that never existed; the promise has been removed rather than left standing.
One text, several places. The English text of this policy is generated from a single source file into the copy bundled in the Android app and the page at hazely.nl/privacy, so those two cannot disagree. The Dutch text is generated the same way into hazely.nl/privacybeleid and into the Android app for devices set to Dutch. The App's own screen headings are still English even when the body text is Dutch. iOS opens the published web version rather than carrying a copy.
A limitation you should know about. Some text shown in the App — including wording on the age-gate and consent screens — can be replaced remotely through Firebase Remote Config without a new app release. We use this to fix wording quickly. It means we do not keep a snapshot of the exact words you were shown when you gave consent, and so we cannot demonstrate afterwards precisely what any individual user read. We are telling you because Art. 7(1) GDPR makes that our problem, not yours; nothing about it limits any right you have under §9.
14. Contact and complaints
- Privacy questions and rights requests: privacy@hazely.nl
- Data-protection contact: dpo@hazely.nl (a routing alias — see §1)
- Legal: legal@hazely.nl
- Security: security@hazely.nl
- Illegal content and abuse: abuse@hazely.nl
- Postal address: not published. Ask at privacy@hazely.nl and we will send it to you in writing.
- Dutch supervisory authority: Autoriteit Persoonsgegevens, https://autoriteitpersoonsgegevens.nl/en — you may complain to them at any time, and you do not have to contact us first.
Changelog
Version 3.0 — 4 August 2026 (replaces version 2.1 of 21 May 2026)
This is a major version because the previous version described a system we no longer run and, in several places, described data handling that did not match the app. Under Art. 5(1)(a) and Art. 13 GDPR a privacy notice has to be accurate, and correcting an inaccurate notice is itself a material change.
Who we are, at last:
1. The controller is now named — a natural person established in the Netherlands, trading under the name published on the Google Play listing. Version 2.1 pointed at "the publisher identified in the Google Play listing", which told an iOS user or a website reader nothing (§1). 2. No company registration is claimed, because there is none yet. When a Dutch business registration exists, §1 will be updated and this policy reissued (§1). 3. A postal address is available on request rather than published, and §1 and §14 both say so and both give the address to ask at (§1, §14). 4. dpo@hazely.nl is explained rather than left ambiguous: no Data Protection Officer has been designated, none is required, and the address is a routing alias (§1).
Corrections of statements that were not accurate:
5. Search text. Version 2.1 said search queries were "in-memory only — never transmitted". With Analytics on, the raw text of a map search used to be sent to Google. It no longer is: only the number of characters and the number of results are sent, on both platforms. The original claim is true again, and §3.4 states it in the narrow form that is actually true (§3.1, §3.2, §3.4). 6. Strain searches. Text typed into the strain catalogue is sent — to our server and on to Google Gemini when there is no local match. Previously undisclosed, and deliberately separated from the map search so the difference is visible (§3.1). 7. Hosting. Removed "Hetzner Online GmbH or the current VPS provider". Added Google Cloud Functions and Firestore in europe-west1, which is where the data actually is (§5, §6). 8. Anthropic. Removed. No Anthropic service is used; menu scanning uses Google Gemini only (§3.3, §5). 9. Data location. Removed the claims that Firebase Analytics and Crashlytics run in "EU (Frankfurt)" and that Gemini runs in a selected EU region. All three are global services (§6). 10. IP addresses. Removed the claim that IPs are truncated to /24 and /48 on receipt. They are not truncated anywhere in the current system (§3.2, §7, §11). 11. EXIF stripping. Version 2.1's unqualified promise was false at the time — an image the server could not decode was forwarded intact. The server now rejects such an upload, so the promise is true as written (§3.3, §11). 12. Menu-scan retention. "Server memory only" corrected to the actual database record, and the 30 minutes is now enforced by a time-to-live policy that deletes the record whether or not anyone reads it again (§3.3, §7). 13. The training claim about menu photos has been removed, not weakened. We do not state that Google does not train on your image, because we have not established that we may (§3.3). 14. "We collect no record of which coffeeshop you visited" — removed, because the analytics events contradict it. §3.5 now states the position honestly instead of arguing that Art. 9 GDPR cannot apply (§3.4, §3.5). 15. Security section rewritten for the Firebase architecture; the Nginx, localhost:8080, chmod 600 and unattended-upgrades description was removed (§11). 16. Breach notification reframed to a public communication under Art. 34(3)(c), because the App has no way to contact you individually (§11). 17. Retention promises removed that had no implementation: the AI-call audit log, nightly backups, the seven-day deletion service level, and the 24-month period for owner requests (§7). 18. AdMob re-described as an independent controller for advertising, not as a processor under Art. 28 GDPR — and the whole advertising section rewritten to say plainly that nothing runs today (§4.3, §5). 19. The blanket Art. 28 assurance was dropped. We do not claim every recipient is bound by a processing agreement, because we have not verified it for every recipient (§5). 20. Legal bases corrected: Art. 6(1)(c) removed for the age gate and the acceptance log; Art. 6(1)(f) used instead, which gives you a right to object that the old basis did not (§4.1). 21. Art. 8 GDPR citation removed from the children section (§12). 22. Feedback forms and crash-reporter comments removed — neither exists (§3.1). 23. The archive promise removed. hazely.nl/privacy/archive never existed; earlier versions are available on request instead (§13).
Newly disclosed processing that was previously missing:
24. Firebase Performance Monitoring, including its automatic network-request traces, and the fact that it has no control of its own (§3.2, §4.1, §10). 25. Firebase Remote Config and Firebase installation identifiers — now gated behind the consent screen on both platforms, where version 2.1's iOS build fetched at launch, before the age gate (§3.2, §4.1). 26. Firebase App Check / Google Play Integrity, which runs even if you reject everything optional (§3.2, §4.1). 27. The Google Play in-app update check, which runs before the age gate (§3.2). 28. GitHub, Inc. as a recipient of crash titles (§3.2, §5). 29. Microsoft Exchange Online as the recipient of everything emailed to our published addresses (§5, §6). 30. The Android Advertising ID, collected by the Analytics SDK under the Analytics switch rather than the ads switch (§3.2). 31. Mapbox Maps SDK telemetry — now switched off on Android unless you consented to Analytics, still not gated on iOS, and with the residual monthly-active-user event disclosed (§3.2, §4.1, §10). 32. The on-device 50-metre proximity check around coffeeshops (§3.2). 33. Permanent storage of AI-generated strain entries derived from scans and searches (§3.3, §7). 34. The full analytics event list, parameter by parameter (§3.2).
New sections:
35. §3.6 — an Art. 14 GDPR notice for people whose data we did not get from them: Google review authors, people in listing photos, and bystanders in menu photos, including the two things about it we cannot yet state as we would like. 36. §4 — a single table giving purpose, data, lawful basis, recipients and retention together, and §4.2, the Art. 13(2)(e) statement of what happens if you decline. 37. §8.2 — AI transparency under Art. 50 of the EU AI Act, applicable since 2 August 2026. Both platforms now show the AI notice before the camera opens; version 2.1's Android build showed it only with the result. 38. §9 — the Art. 11(2) GDPR limitation on access, erasure and portability, stated openly rather than promising rights the architecture cannot deliver. 39. §13 — an honest description of what re-prompts you on each platform, and the fact that in-app wording can be changed remotely.
Known defects we have chosen to publish rather than paper over: the merged Android "Analytics & Performance" switch (§10), the absence of version tracking on iOS (§13), the absence of an in-app data-rights link on Android (§9), the absence of a visible "AI-generated" label on generated strain entries (§8.2), the absence of a retention limit on cached shop reviews (§3.6), and the fact that consent-screen wording can be changed remotely (§13). Each of them is a thing to fix, and each is described here in the form it actually takes today.
- 3.1 (13 August 2026). iOS: the personalised-ads switch was removed from the consent screen and Settings after App Store review feedback (Guideline 5.1.2(i)). The iOS App has no advertising SDK and performs no tracking; the switch controlled nothing and implied otherwise. Android is unchanged. Section 10's toggle table was corrected to match.
- 3.2 (14 August 2026). Corrections and forward notices, in both languages. §11 no longer claims App Check lets us "tell a real installation from a script": the app does attach a Play Integrity token, but server-side enforcement of those tokens is currently switched off, so the sentence now describes a defence-in-depth measure, not a guarantee, and notes that enforcement may be switched on without notice. §10's iOS row was incomplete: Firebase Performance rides the Analytics switch on iOS too, and the row now names both switches correctly. §6 no longer asserts which transfer instrument covers each recipient; it is hedged the way §5 hedges processing agreements, pointing at the practical protections instead. The version 3.1 entry referred to the toggle table as Section 14; it is Section 10, and the reference is fixed. Forward notes added: from Android 1.0.7 and the next iOS build the shop-name parameter leaves all analytics events (the shop ID remains) and iOS's
strain_viewedswitches to the strain ID (§3.2); Advertising-ID collection is disabled from Android 1.0.7 (§3.2); and the next releases add the in-app data-request link on Android and an "App instance ID" display, with copy, on both platforms (§9). §7 now discloses a one-off manual cleanup (August 2026) of a small number of legacy scan records that predate the expiry field.