Integrating Mitr Analytics β a guide for AI coding assistants
This page is written to be handed directly to an AI assistant (Claude,
ChatGPT, Copilot, Cursor, etc.) β pasted into a chat, or fetched by an
agent from /docs/ai-integration.md
(plain markdown, same content). Following it end-to-end, an assistant
should be able to fully wire up Mitr Analytics in a client's codebase
without back-and-forth beyond the two questions in Step 1.
Step 1 β Get the two things you need from the human
Ask (only if not already provided):
- Site ID β a UUID from the Mitr dashboard (Integration Hub β their app's card, or the "SDK Setup" step of the "Add New App" wizard).
- Platform β a website (plain HTML or a JS framework), or a Flutter app (iOS/Android/desktop)? Flutter also needs the Secret Key from the same dashboard screen.
Web snippets load the SDK from https://mitranalytics.dev/vendor/mitr.js,
the canonical URL. Events go to https://api.mitranalytics.dev/api/v1,
the SDK's built-in default β set data-base-url only to point at a
self-hosted or staging backend. You can also self-host mitr.js
from your own static assets; the API is identical either way.
If the human doesn't have a Site ID yet, tell them: "Go to your Mitr dashboard β Integration Hub β Add New App, choose your platform, and enter your domain (for a website) or bundle/package ID (for an app). You'll get a Site ID immediately, plus a Secret Key if you chose a non-web platform." You cannot generate a Site ID yourself.
Do not invent a placeholder Site ID and ship it. Use a literal placeholder like YOUR_SITE_ID until the human gives you a real one.
Step 2 β Detect the platform (if not already told)
| You find... | Platform | Go to |
|---|---|---|
pubspec.yaml with flutter: section | Flutter app | Step 3C |
package.json with "next" | Next.js | Step 3B |
package.json with "react" (no Next) | React SPA | Step 3B |
package.json with "vue" / "nuxt" | Vue / Nuxt | Step 3B |
Plain .html files, no framework | Static site | Step 3A |
| WordPress/Shopify/Webflow/Squarespace/Wix (human describes it) | No-code platform | Step 3A (no-code variant) |
| No JS repo at all | Ask which of the above, or default to Step 3A no-code variant | β |
Step 3A β Plain HTML / static site / no-code platform
Paste this once, right before </head> or the closing </body> tag:
<script src="https://mitranalytics.dev/vendor/mitr.js"
data-site-id="YOUR_SITE_ID"
async defer></script> That's it β no other code required. It auto-tracks page views, including client-side route changes if the site later adds one.
No-code platforms (WordPress, Shopify, Webflow, Squarespace, Wix): the human pastes the exact same snippet into their platform's "Custom Code" / "Header Scripts" / "Tracking Code" section β every one of these platforms has such a setting.
Do not add a secret key anywhere in web output β it isn't needed and shouldn't be embedded in public HTML/JS.
Step 3B β JS framework (React, Next.js, Vue, Nuxt, etc.)
Add the SDK once near your app's root/entry point β not to every page/component.
Plain script tag (simplest, works anywhere):
<script src="https://mitranalytics.dev/vendor/mitr.js" data-site-id="YOUR_SITE_ID" async defer></script>
Next.js (App Router) β app/layout.jsx:
'use client';
import Script from 'next/script';
export default function RootLayout({ children }) {
return (
<html><body>
{children}
<Script src="https://mitranalytics.dev/vendor/mitr.js" data-site-id="YOUR_SITE_ID" strategy="afterInteractive" />
</body></html>
);
} React SPA β call once at startup instead of a script tag, if preferred:
useEffect(() => { window.Mitr.init('YOUR_SITE_ID'); }, []); Auto-tracking already covers client-side route changes β no per-route tracking calls needed for React Router, Vue Router, or similar.
Custom events, wherever the relevant action happens:
window.Mitr.track('signup_completed', { plan: 'pro' }); On login/logout, if the app has auth:
window.Mitr.identify(user.id); // after login window.Mitr.reset(); // on logout
Full API reference: JavaScript SDK.
Step 3C β Flutter app (iOS / Android / desktop / Flutter Web)
-
Add the dependency (adjust the path to wherever this SDK lives
relative to the client's project β tell the human it needs to be
vendored locally, since it isn't on pub.dev yet):
dependencies: mitr_flutter: path: ../path/to/mitr-sdk-suite/mitr_flutterThen runflutter pub get. -
Initialize once, at the top of
main(), using both the Site ID and Secret Key from Step 1:import 'package:mitr_flutter/mitr_flutter.dart'; Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await MitrAnalytics.instance.initialize( siteId: 'YOUR_SITE_ID', secretKey: 'YOUR_SECRET_KEY', ); runApp(const MyApp()); } -
Add automatic screen tracking to the app's router:
MaterialApp( navigatorObservers: [MitrNavigationObserver()], // ... )
(Useobservers:instead if the app usesGoRouter.) -
Custom events, wherever relevant:
await MitrAnalytics.instance.track('purchase_completed', meta: {'value': 49.99}); -
On login/logout, if the app has auth:
MitrAnalytics.instance.identify(user.id); // after login MitrAnalytics.instance.reset(); // on logout
Full API reference: Flutter SDK.
Step 4 β Verify it worked
- Run the site/app and navigate around.
- In the Mitr dashboard β Integration Hub, open the app's card and click "Check connection" β it should flip from "Pending" to "Connected" within a few seconds of the first event being sent.
-
If it doesn't:
- Web: open devtools β Network tab, find the request to
.../api/v1/event. A403means the page's domain doesn't match what was registered (common cause: testing on a different domain/subdomain βlocalhostis always allowed in non-production environments). A404means the Site ID is wrong or the app was deleted. - Flutter (debug builds): check the console β
initialize()fires a diagnostic ping and logs the result immediately, most commonly flagging a wrong Secret Key.
- Web: open devtools β Network tab, find the request to
Things to never do
- Never put a Flutter/mobile Secret Key into web-facing HTML/JS β web doesn't need one and it would be publicly visible in page source.
- Never pass a raw email, name, or other PII into
track/identify/pageViewmetadata β only pass an opaque user id toidentify; the SDK hashes it before it's sent. - Never call
init/initializemore than once per app instance, and never block app startup waiting on it β both SDKs degrade gracefully (queue locally, retry later) if the network or backend is temporarily unavailable.