Skip to content

Native apps

A native app has no <script> tag to load lytics.js into, so it talks to /ingest directly. The endpoint is a plain JSON POST with no key on it, which is the whole integration — there is no native SDK to install.

Two fields separate app traffic from website traffic in the same project:

  • platform"ios" or "android". The browser snippet sends "web".
  • app — which client sent it, e.g. "myapp-mobile". Lowercase letters, digits, ., _ and -, up to 64 characters. Websites set the same tag with data-app.

Both show up in the dashboard’s Devices & apps card.

await fetch("https://api.analytics.canarycoders.es/ingest", {
method: "POST",
headers: {
"Content-Type": "application/json",
// Native requests carry no Origin of their own, and ingest checks it
// against the project's trusted domains. Send the product's own origin.
Origin: "https://myapp.com",
},
body: JSON.stringify({
domain: "myapp.com", // must be one of the project's trusted domains
sessionId, // UUID v4, see below
eventType: "page_view", // or "custom" with an eventName
path: "/hotspot/teide", // the app's own route
platform: "ios",
app: "myapp-mobile",
deviceType: "mobile", // or "tablet" — the app knows, no UA to read it off
locale: "en-GB",
}),
});

Ingest answers 204 to everything, including rows it drops, so there is nothing to branch on. Fire and forget.

The browser snippet scopes a session to a tab (sessionStorage). An app has no tab, so mint a UUID v4, persist it, and rotate it after a stretch of inactivity — 30 minutes is the usual choice and what CanaryPulse’s own app uses. Sessions are how unique visitors are counted, so a single id that never rotates collapses the whole install into one visitor forever.

What the server does differently for native events

Section titled “What the server does differently for native events”
  • No bot classification. React Native’s default Android user agent is a bare okhttp/4.12.0, which every bot list matches. Native events skip the check outright rather than being labelled crawlers and hidden from stats.
  • os comes from the platform tag (ios → iOS, android → Android) since there is no browser UA to parse, and browser stays empty.
  • deviceType comes from the app, falling back to mobile when it is not sent.

Report the app’s own routes. They will not match the website’s URLs — /hotspot/teide in an app against /en/hotspots/tenerife/h/teide on the web — so Top pages lists both shapes side by side and the app tag is what tells them apart. Rewriting native routes into web URLs is rarely worth the mapping code.