Setup: one line
Register the landing page as its own app in the dashboard (+ New app,
a slug like myappweb), then add one line before </body>:
<script src="https://foliokit.io/appcore-web.js"
data-app-id="YOUR_SLUG" data-api-key="YOUR_API_KEY" defer></script>
That's everything. The landing page gets linked to its iOS app so the app's Overview shows a Landing card — the web→store funnel, per-page views and time, visitor countries, referrers, and campaigns. During early access, the linking is done for you: mention which app the page belongs to when you register it, or email contact@foliokit.io.
What gets tracked automatically
| Event | When |
|---|---|
page_view | page load — with the page path, campaign/source from the URL (see below), and the referrer's hostname |
store_click | a click on any link to apps.apple.com — your web→store conversion |
page_leave | leaving the page, carrying the visitor's visible time on it — background tabs don't count, so "average time on page" means time actually looking at it |
Campaign links: ?ac=
When you post a link on Reddit, a newsletter, or anywhere else, append
?ac=campaign-name:
https://yourapp.com/?ac=reddit-launch
Every page_view (and the store_click that may follow)
carries that campaign, and the Landing card breaks visitors down by it. The snippet
also reads standard ?utm_campaign= / ?utm_source= /
?ref= parameters, so existing tagged links keep working.
Custom events: one attribute
Put data-appcore-event="name" on any element to count its clicks:
<button data-appcore-event="pricing_expanded">See pricing</button>
The waitlist-form pattern
For a simple "how many people clicked join" count, the attribute above is enough. If you want the signup itself — including the email — as an event, post it directly from your form's submit handler. This is exactly how foliokit.io's own waitlist works:
await fetch("https://foliokit.io/api/track", {
method: "POST",
headers: { "content-type": "text/plain" },
body: JSON.stringify({
app_id: "YOUR_SLUG",
api_key: "YOUR_API_KEY",
user: { id: uid }, // reuse localStorage "appcore_uid" if present
events: [{ name: "waitlist_signup",
screen: location.pathname,
props: { email: cleanedEmail } }],
}),
})
Signups then show up highlighted in the Live tab, email included, seconds after
they happen. Putting an email in props is your call — it's your event data, on your
app; the SDK-side rule of "no PII in props" exists because app events don't need
it, but a waitlist signup is the email. The text/plain
content type is deliberate: it keeps the request a CORS "simple request" so
browsers deliver it reliably, even during page unload.
How geography works (the relay)
The snippet sends events to foliokit.io/api/track, a tiny edge relay
whose only jobs are to stamp the visitor's country (from the network edge — no IP
is stored, no geolocation API runs in the browser) and forward the event to
ingestion. That's why the Landing card can show a country breakdown without any
fingerprinting.
Honesty section: adblockers
Brave, uBlock Origin, and most content blockers block requests like this one — those visitors are invisible to the snippet, full stop. If your audience is developers, the undercount can be significant. FolioKit will not play the cat-and-mouse games (disguised endpoints, fingerprinting) that "fix" this; treat web numbers as a directional floor, not a census. Your App Store click counts are affected the same way, so the web→store ratio stays roughly honest.
Privacy & safety
- The visitor ID is a random anonymous string in
localStorage— no cookies, no fingerprinting, no personal data collected by the snippet itself. - The API key is send-only: it can add events for your page and read nothing.
- Tracking failures can never break the page — every call is wrapped and fire-and-forget.
The full collected/never-collected list is on the data & privacy page.