Cookie Policy
Last updated: August 6, 2026
This Cookie Policy explains how AR Menu ("we," "us," or "our") uses cookies, localStorage, sessionStorage, IndexedDB, and similar browser storage technologies (collectively, "cookies and similar technologies") on our Platform: the restaurant dashboard at dashboard.armenu.me, the diner-facing menu application at menu.armenu.me, the marketing website at armenu.me, and the backend API at api.armenu.me.
This policy should be read together with our Privacy Policy, which explains how we process personal data more broadly, and our Terms of Service.
1. What Are Cookies and Similar Technologies?
A cookie is a small text file that a website stores on your device (computer, phone, tablet) through your web browser. Cookies may be:
- First-party cookies: Set by the domain you are visiting directly (e.g., a cookie set by
armenu.mewhen you visitarmenu.me). - Third-party cookies: Set by a domain different from the one you are visiting (e.g., a cookie set by
stripe.comembedded onarmenu.me). - Session cookies: Temporary cookies that are deleted when you close your browser.
- Persistent cookies: Cookies that remain on your device for a set period or until you manually delete them.
In addition to traditional cookies, we use Web Storage APIs built into modern browsers:
localStorage: Stores data with no expiration date. Data persists until explicitly cleared by the website or the user. Accessible only by JavaScript running on the origin that stored it.sessionStorage: Stores data for the duration of a browser tab session. Data is cleared when the tab is closed. Like localStorage, it is origin-scoped.IndexedDB: A low-level API for storing significant amounts of structured data, including files and blobs. Used by the menu PWA (Progressive Web App) for offline caching of dish images, 3D models, and menu data via the Workbox service worker.
Throughout this policy, we refer to all of these technologies collectively as "storage mechanisms" and specify which technology is used for each purpose.
2. Cookies and Storage We Use — Overview
Below is a complete inventory of every storage mechanism set by the AR Menu Platform, organized by category. We do not use any storage mechanisms beyond those listed here.
| Name / Key | Technology | Domain | Category | Purpose | Duration |
|---|---|---|---|---|---|
csrf_access_token |
Cookie (httpOnly, SameSite=Strict, Secure) | api.armenu.me | Necessary | CSRF protection for state-changing requests (POST, PUT, PATCH, DELETE). Contains a cryptographically random token verified against a matching header. | Session (deleted when browser closes) |
refresh_token_cookie |
Cookie (httpOnly, SameSite=Strict, Secure, Path=/api/auth) | api.armenu.me | Necessary | Stores the JWT refresh token for silent token renewal. httpOnly prevents JavaScript access. Restricted to auth endpoints. Revocable server-side. | 30 days (or until revoked) |
__cf_bm |
Cookie | .armenu.me (Cloudflare) | Necessary | Cloudflare bot management — distinguishes human traffic from bots. Required for DDoS protection. Does not track users across sites. | 30 minutes |
armenu_lang |
localStorage | armenu.me | Necessary | Stores the user's language preference (en/fr/ar) for the landing page. Set when user clicks a language button. | Persistent (until manually cleared) |
armenu_session_id |
sessionStorage | menu.armenu.me | Necessary | Temporary session identifier for the diner menu application. Links page views during a single browsing session. Used for QR-to-menu routing. Not persisted across sessions. | Session (cleared when tab closes) |
armenu_diner_id |
localStorage | menu.armenu.me | Functional | Randomly generated UUID assigned to each unique diner. Allows us to distinguish returning diners from new ones for analytics (e.g., "how many unique diners scanned a QR code this week"). Not linked to personal identity unless the diner voluntarily provides name/email for an order. | Persistent (until manually cleared) |
armenu_last_restaurant |
localStorage | menu.armenu.me | Functional | Stores the slug of the last restaurant a diner visited. Enables the "Continue browsing [Restaurant]?" convenience prompt on return visits. | Persistent (until manually cleared) |
fingerprint_visitor_id |
localStorage | menu.armenu.me | Functional | Hash computed by FingerprintJS from browser characteristics. Used for fraud prevention (detecting automated scanners) and unique diner counting. Computed client-side; the raw fingerprint data never leaves the browser — only the final hashed visitor ID is stored and transmitted. | Persistent (until manually cleared) |
workbox-precache-* |
IndexedDB / CacheStorage | menu.armenu.me | Necessary | PWA service worker cache (Workbox). Stores pre-cached app shell (HTML, CSS, JS) and runtime-cached images, 3D models, and menu data for offline access. Managed by the browser; automatically purged when storage quota is reached. | Managed by browser (LRU eviction) |
Note on third-party cookies: We do not use any advertising cookies, retargeting pixels, social media trackers, or cross-site tracking cookies. We do not integrate with Google Analytics, Facebook Pixel, or any analytics service that uses third-party cookies.
3. Category 1: Necessary Storage (Always Active)
These storage mechanisms are essential for the Platform to function and cannot be disabled. They are set in response to actions you take that amount to a request for services, such as logging in, setting language preferences, or loading a menu from a QR code. Under the ePrivacy Directive (EU) and PECR (UK), these are exempt from the consent requirement.
| Storage Key | Where Set | What It Does | Data Stored |
|---|---|---|---|
csrf_access_token |
All authenticated API requests | Prevents Cross-Site Request Forgery attacks. Every state-changing request (POST, PUT, PATCH, DELETE) to our API must include a matching X-CSRF-TOKEN header. Without this cookie, the API would be vulnerable to forged requests from malicious sites. | A cryptographically random string (not derived from any user data) |
refresh_token_cookie |
Login endpoint (api.armenu.me) | Enables silent token renewal without requiring the user to re-enter their password every 15 minutes (the access token lifetime). httpOnly means it cannot be read by JavaScript — even if XSS were present, the refresh token could not be exfiltrated. Revocable server-side via the refresh_tokens database table. | JWT refresh token (signed, contains user ID and token JTI) |
__cf_bm |
All *.armenu.me domains | Cloudflare's bot detection cookie. Uses a proof-of-work challenge to distinguish human browsers from automated scripts and bots. Critical for DDoS mitigation and API abuse prevention. | Bot detection token (Cloudflare-managed) |
armenu_lang |
Landing page (armenu.me) | Remembers which language you selected (English, French, or Arabic) so the landing page renders in your preferred language on return visits. Without this, the page would always default to English. | String: "en", "fr", or "ar" |
armenu_session_id |
Diner menu app (menu.armenu.me) | Ties together page views during a single menu browsing session. When a diner scans a QR code, the QR token (restaurant + table) is associated with this session ID for the duration of the tab. Essential for routing orders to the correct table. | Randomly generated UUID v4 |
workbox-precache-* |
Menu PWA (menu.armenu.me) | The service worker cache that makes the menu app work offline and load instantly on repeat visits. Stores the app shell (HTML, CSS, JavaScript bundles) and, at runtime, caches dish images and 3D models after first load. Without this, the menu app would require a network connection for every page load — impractical in many restaurant settings with poor connectivity. | Static assets (HTML, CSS, JS), runtime-cached images and 3D models |
4. Category 2: Functional and Analytics Storage (Consent-Based)
These storage mechanisms are not strictly necessary for the Platform to function but enhance the experience and provide us with aggregated insights. Under the ePrivacy Directive and GDPR, these require your consent. These are set only after you accept them — either through our cookie banner (where implemented) or implicitly through using features that require them (such as return visits to the menu app).
| Storage Key | Where Set | What It Does | Data Stored |
|---|---|---|---|
armenu_diner_id |
Diner menu app (menu.armenu.me) | A persistent, randomly generated identifier that allows us to count unique diners over time. When a restaurant owner views their analytics dashboard, metrics like "124 unique diners this week" are derived from counting distinct diner IDs. Without this, every page refresh would count as a new diner. The ID is pseudonymous — it is not linked to a name, email, phone number, or any real-world identity unless the diner explicitly provides that information (e.g., for an order or reservation). | Randomly generated UUID v4 |
armenu_last_restaurant |
Diner menu app (menu.armenu.me) | Remembers the last restaurant you browsed. On return to menu.armenu.me, shows a "Continue browsing [Restaurant Name]?" prompt. A convenience feature — if you regularly visit the same restaurant, you do not need to re-scan the QR code. |
Restaurant slug (e.g., "le-jardin-marrakech") |
fingerprint_visitor_id |
Diner menu app (menu.armenu.me) | A hash computed from browser characteristics by the FingerprintJS library. Used for fraud prevention (detecting bots or scripts that simulate QR scans) and accurate unique visitor counting (browsers that clear localStorage would otherwise be double-counted; fingerprinting provides a secondary identifier). The raw browser characteristics are hashed client-side — only the final hash is stored. See Section 6 for a full explanation. | SHA-256 hash of browser fingerprint components |
5. Category 3: Third-Party Services and Their Data Flows
In addition to the first-party storage mechanisms listed above, certain third-party services that our Platform depends on may receive data from your browser as a byproduct of standard HTTP communication. This is not the same as third-party cookies (which we do not use), but we disclose it here for transparency.
| Service | What Happens | Data Transmitted | Cookies Set? |
|---|---|---|---|
| Google Fonts (fonts.googleapis.com, fonts.gstatic.com) |
When you load any AR Menu page, your browser requests font files (Inter and Playfair Display) from Google's CDN. The CSS @font-face rules are loaded from fonts.googleapis.com; the actual font binaries from fonts.gstatic.com. |
IP address, User-Agent string, Referrer header (the AR Menu page URL). Google states that Fonts API data is not used for advertising, profiling, or tracking. No authentication cookies are sent. | No cookies are set by the Google Fonts API. |
| jsDelivr CDN (cdn.jsdelivr.net) |
On diner pages that support 3D model viewing, the @google/model-viewer library is loaded from jsDelivr, a public CDN. No cookies are set by jsDelivr. |
IP address, User-Agent string, Referrer header. jsDelivr uses this for CDN routing and aggregate usage statistics. | No cookies are set by jsDelivr on our domains. |
| Cloudflare (*.armenu.me) |
All traffic to our Platform passes through Cloudflare's edge network. Cloudflare sets the __cf_bm cookie (see Category 1) for bot management. Cloudflare may also use other transient challenge cookies as part of DDoS protection. |
IP address, User-Agent, full request URL, Referrer. Processed at Cloudflare's edge for security, caching, and analytics. Logs retained per Cloudflare's policy (typically 24 hours at the edge). | __cf_bm (30 min, necessary). No tracking cookies. |
| Stripe (stripe.com, js.stripe.com) |
On the pricing page and dashboard payment screens, Stripe's JavaScript library and checkout components are loaded. Stripe may set cookies on its own domains for fraud detection (Radar). Stripe does not set cookies on our domains. | IP address, User-Agent, payment form interaction data. Stripe's fraud detection (Radar) evaluates browser characteristics. Full card numbers are tokenized before reaching our servers. | Stripe sets cookies on stripe.com only (third-party context). See Stripe's cookie policy. |
| FingerprintJS (fingerprint.js.org — loaded from jsDelivr) |
The FingerprintJS library (v3) is loaded in the diner menu app. The library executes in the browser and computes a browser fingerprint. The raw fingerprint data is hashed client-side using SHA-256. Only the resulting hash (visitor ID) is stored in localStorage and transmitted to our servers. The raw fingerprint characteristics never leave the browser. See Section 6. | No data transmitted to FingerprintJS servers. The library runs entirely client-side. The hashed visitor ID is stored in our Supabase database. | No cookies or storage set by FingerprintJS on any domain. |
6. FingerprintJS — Browser Fingerprinting in Detail
What Is Browser Fingerprinting?
Browser fingerprinting is a technique that identifies a unique browser instance by combining dozens of characteristics that browsers expose: screen resolution, installed fonts, WebGL renderer string, canvas rendering output, audio processing fingerprint, list of installed browser plugins, HTTP Accept headers, timezone, and more. When combined, these characteristics form a "fingerprint" that is statistically unique — like a digital fingerprint for your browser.
6.1 Why We Use Fingerprinting
We use FingerprintJS (an open-source library, v3, loaded from jsDelivr CDN) on the diner menu application for two specific purposes:
- Fraud prevention: Detecting automated scripts or bots that scan QR codes programmatically to harvest menu data, place fake orders, or abuse the platform. Browser fingerprints help distinguish legitimate diner browsers from headless browsers, Selenium scripts, or other automation tools.
- Accurate unique visitor counting: When a diner clears their browser data (including the
armenu_diner_idfrom localStorage), we would otherwise count them as a new unique diner on their next visit. The browser fingerprint provides a secondary, more stable identifier — allowing us to deduplicate and provide restaurants with more accurate analytics ("this diner who cleared their cookies is the same person who visited yesterday").
6.2 How It Works — Technical Details
- The FingerprintJS library (approximately 18 KB gzipped) loads in the diner's browser when they first access a menu.
- The library collects approximately 30 browser characteristics: Canvas fingerprint (how the browser renders a hidden test image), WebGL vendor and renderer string, installed fonts (via font enumeration), audio context fingerprint, screen resolution and color depth, list of navigator plugins, platform and User-Agent, language, timezone, touch support, and more.
- These characteristics are combined and hashed using SHA-256 entirely within the browser. The raw characteristic values are never transmitted to our servers or to any third party.
- The resulting 64-character hexadecimal hash (e.g.,
a1b2c3d4e5f6...) is stored in localStorage under the keyfingerprint_visitor_idand may be included in API requests to our backend. - Our backend stores this hash in the diner_sessions table alongside the session data. The hash cannot be reversed to reconstruct the original browser characteristics.
6.3 Privacy Implications
- No cross-site tracking: Our use of FingerprintJS is limited to our own domains (
menu.armenu.me). The visitor ID does not follow you to other websites. We do not participate in any cross-site fingerprinting network. - No raw data leaves the browser: The browser characteristics are computed and immediately hashed client-side. The raw characteristics (canvas image, font list, etc.) are discarded. Only the hash is stored.
- Not linked to real identity: The fingerprint hash is a pseudonymous identifier. We do not link it to a name, email, phone number, or any real-world identity unless the diner explicitly authenticates (e.g., creates an account — a feature not currently available to diners).
- Opt-out: You can prevent fingerprinting by blocking JavaScript on our menu domain (though this will break the AR and 3D viewing features) or by using a browser with fingerprinting protection (Brave, Firefox with ResistFingerprinting, Safari with Advanced Tracking Protection). Clearing localStorage also removes the stored fingerprint hash, though a new one will be computed on the next visit.
6.4 FingerprintJS vs. Fingerprint Pro
We use the open-source FingerprintJS library (v3), not Fingerprint Pro. The open-source version operates entirely in the browser — no data is sent to FingerprintJS Inc. servers. We do not have a commercial relationship with FingerprintJS Inc. and they do not receive any data from our use of their open-source library.
7. How to Manage, Delete, or Block Cookies
7.1 Browser Settings
All major browsers allow you to manage cookies and site data. You can typically:
- View all cookies and site data stored by a website.
- Delete specific cookies or all cookies from a domain.
- Block all cookies (may break site functionality).
- Block third-party cookies specifically.
- Automatically clear cookies when the browser closes.
- Use private/incognito mode (cookies and site data are automatically cleared when the private window closes).
Instructions for common browsers:
- Google Chrome: Settings → Privacy and security → Cookies and other site data → See all site data and permissions
- Mozilla Firefox: Preferences → Privacy & Security → Cookies and Site Data → Manage Data
- Safari: Preferences → Privacy → Manage Website Data
- Microsoft Edge: Settings → Cookies and site permissions → Manage and delete cookies and site data
- Brave: Settings → Shields → Cookie blocking; Settings → Privacy and security → Clear browsing data
7.2 Clearing Web Storage (localStorage and sessionStorage)
Browser cookie management interfaces do not always include localStorage and sessionStorage. To clear these:
- Chrome/Edge: Open Developer Tools (F12) → Application tab → Storage → Local Storage / Session Storage → right-click the domain → Clear.
- Firefox: Open Developer Tools (F12) → Storage tab → Local Storage / Session Storage → right-click the domain → Delete All.
- Safari: Develop menu → Show Web Inspector → Storage tab → Local Storage / Session Storage.
7.3 Clearing PWA Cache (IndexedDB / CacheStorage)
The menu PWA at menu.armenu.me caches assets for offline use. To clear this cache:
- Chrome/Edge: Developer Tools → Application → Cache Storage → right-click → Delete. Or, Settings → Privacy → Clear browsing data → Cached images and files.
- Alternative: In the browser, visit
menu.armenu.me, open Developer Tools → Application → Service Workers → click "Unregister." Then reload the page. The service worker and all its caches will be removed.
7.4 Effect of Blocking Cookies
If you block necessary cookies and storage:
- Dashboard: You will not be able to log in (authentication and CSRF protection depend on necessary cookies).
- Diner menu: The menu will still load and function for browsing, but: language preferences will not persist, the "continue browsing" feature will not work, orders may not route correctly to your table (sessionStorage is required for table identification), and the PWA offline mode will not function.
- Landing page: Language preference will not persist between visits (always defaults to English).
8. How to Withdraw Consent
For Category 2 (Functional) storage mechanisms, you may withdraw your consent at any time. There are several ways to do this:
8.1 Clear Browser Data
The simplest method is to clear all site data for our domains. This removes all localStorage and sessionStorage entries — including the functional ones (diner ID, last restaurant, fingerprint hash). Follow the instructions in Section 7 above. After clearing, the necessary storage mechanisms will be recreated on your next visit (as they are required for the Platform to function); the functional ones will not be recreated unless you implicitly consent again by using the features that require them.
8.2 Browser Fingerprinting Protection
To specifically prevent browser fingerprinting, you can:
- Use Brave Browser — blocks fingerprinting by default.
- Use Firefox with
privacy.resistFingerprinting = truein about:config. - Use Safari with Advanced Tracking Protection enabled (default on macOS and iOS).
- Use browser extensions that block or spoof fingerprinting scripts.
Note that fingerprinting-resistant browsers may cause the Platform to incorrectly classify your visits or may prevent AR/3D features that rely on WebGL (which is often disabled or spoofed by fingerprinting protections).
8.3 Cookie Consent Banner
Where required by law (EU/EEA, UK, California, and other jurisdictions with consent requirements), we display a cookie consent banner on first visit, allowing you to accept or reject Category 2 storage mechanisms. Your preference is stored and respected for 12 months, after which the banner will reappear. You can change your preference at any time by clearing site data and revisiting the page (the banner will reappear).
9. What Third-Party Services Receive Your Data
The following table summarizes which third-party services receive data from your browser when you use the Platform, either through cookies/storage or as a byproduct of HTTP requests. This repeats and consolidates information from Sections 2-6 for clarity.
| Service | Data Received | Purpose | How to Opt Out |
|---|---|---|---|
| Google Fonts | IP address, User-Agent, Referrer | Font file delivery | Use a browser extension that blocks Google Fonts; self-host fonts (we plan to do this in a future update) |
| jsDelivr CDN | IP address, User-Agent, Referrer | JavaScript library delivery (model-viewer, FingerprintJS) | Block jsDelivr at the network level; 3D/AR features and fingerprinting will not function |
| Cloudflare | IP address, User-Agent, full URL, Referrer | CDN, DDoS protection, bot detection | Cannot be opted out — all traffic passes through Cloudflare. Without it, the Platform would be unavailable. |
| Stripe | IP address, User-Agent, payment interaction data | Payment processing and fraud detection | Do not use paid subscription features. Stripe is only loaded on payment pages. |
| Meshy AI | Dish photographs (uploaded by restaurant owners only) | 3D model generation | Do not use the 3D model generation feature. Only the specific photographs you upload for 3D generation are sent. |
| Supabase | All Platform data (see Privacy Policy) | Database and API hosting | Cannot be opted out — the entire Platform depends on Supabase. |
| Sentry | IP address, User-Agent, error data (PII scrubbed) | Error monitoring | No browser-visible interaction; Sentry receives data from our backend, not directly from your browser. |
10. Changes to This Cookie Policy
We may update this Cookie Policy from time to time. When we make material changes, we will update the "Last updated" date at the top of this page. For significant changes (e.g., adding a new third-party service that sets cookies or introducing new tracking mechanisms), we will also notify restaurant owners via email and display a notice on the Platform. We encourage you to review this policy periodically. Continued use of the Platform after changes are posted constitutes acceptance of the updated policy.
The full version history of this policy is maintained in our internal records and available upon request to dpo@armenu.me.
11. Contact
Questions About Cookies?
If you have questions about this Cookie Policy, our use of cookies and similar technologies, or your privacy choices, please contact us:
AR Menu — operated by Nourdine Ouakhroun
Email (privacy): dpo@armenu.me
Email (general): contact@armenu.me
Website: https://armenu.me
Full Privacy Policy: /privacy