Framer Integration
Add Zenovay to any Framer site through Site Settings → Custom Code. The snippet only fires on the published site — preview ignores Custom Code, which is normal.
Custom Code is available on all Framer paid plans (Mini and above). Free Framer sites can't add third-party scripts.
Quick Start
| Step | Where | What you do |
|---|---|---|
| 1 | Zenovay dashboard | Copy your tracking snippet |
| 2 | Framer → Site Settings → General → Custom Code | Paste it into Start of <head> tag |
| 3 | Publish | Click Publish in the top-right corner |
| 4 | Zenovay dashboard | Real-time visitors appear within ~30 seconds |
Method 1: Site-wide Custom Code (Recommended)
Framer's Custom Code panel injects HTML directly into every published page. It's the supported approach for any analytics or marketing tag.
Step-by-step
- Open your project in Framer.
- Click Site Settings (gear icon at the top of the left panel).
- Open the General tab if it isn't already.
- Scroll to Custom Code.
- In Start of
<head>tag, paste:
<script defer data-tracking-code="YOUR_TRACKING_CODE" src="https://api.zenovay.com/z.js"></script>
- Click outside the field to save automatically.
- Click Publish in the top-right of the editor. Custom Code does not apply to the preview URL — only to the live published site.
Verify
Open the published Framer URL (*.framer.app or your custom domain) in incognito and view source. You should see <script defer data-tracking-code=...> near the top of <head>. Your visit should appear in the Zenovay real-time view within ~30 seconds.
Method 2: Per-page Custom Code
For page-specific tracking (e.g. only your campaign landing pages), Framer also exposes per-page Custom Code:
- Select the page in the Pages panel.
- Open the page's right-side panel and scroll to Custom Code.
- Paste the snippet into Start of
<head>tag for that page. - Publish.
Per-page Custom Code is appended after site-wide code. Don't paste the tracker in both — you'll double-count.
Tracking custom events
Framer renders pages as a React SPA, but the tracker handles SPA navigation automatically (it listens for history.pushState). For custom events you can call window.zenovay() from any Framer Code Override or Code Component.
Track a CTA click with a Code Override
Create a new Code Override in Framer:
import type { ComponentType } from 'react';
export function withCtaTracking(Component): ComponentType {
return (props) => {
return (
<Component
{...props}
onClick={(e) => {
props.onClick?.(e);
// @ts-ignore – global injected by tracker
window.zenovay?.('track', 'cta_clicked', {
location: props.id || 'unknown',
page: typeof window !== 'undefined' ? window.location.pathname : '',
});
}}
/>
);
};
}
Apply the override to your CTA frame via Frame → Code Overrides → withCtaTracking.
Track form submissions
Framer Forms submit through a hidden iframe. Listen for the form's submit event in a Code Override or in a global override attached to the page root:
import { useEffect } from 'react';
export function useTrackFormSubmits() {
useEffect(() => {
const handler = (e: Event) => {
const form = e.target as HTMLFormElement;
if (!form?.matches('form')) return;
// @ts-ignore
window.zenovay?.('track', 'form_submitted', {
form_id: form.id || form.getAttribute('name') || 'unnamed',
page: window.location.pathname,
});
};
document.addEventListener('submit', handler, true);
return () => document.removeEventListener('submit', handler, true);
}, []);
return null;
}
Identify logged-in users (if you use Framer Auth or a third-party)
If you've wired Framer to an external auth provider (Memberstack, Outseta, Clerk, etc.), call window.zenovay('identify', ...) from the auth provider's onSignIn callback. There is no native auth in Framer to hook directly.
Plan requirements
| Plan | Custom Code | Custom domain |
|---|---|---|
| Free | ❌ | ❌ |
| Mini | ✅ | ✅ |
| Basic | ✅ | ✅ |
| Pro | ✅ | ✅ |
| Business | ✅ | ✅ |
Common gotchas
Preview ignores Custom Code. This is the #1 surprise. The Framer editor preview (the play button) renders the page without your Custom Code. You must click Publish and test the live URL — testing the preview will always show "no Zenovay script loaded".
Localhost / custom domains. If you're using a custom domain through Framer's hosting, Custom Code works the same as on *.framer.app. If you're exporting Framer to self-host as static HTML, you'll need to paste the snippet into your exported index.html manually — Framer's static export doesn't currently include Custom Code in the bundle.
SPA navigation is handled. Framer is React under the hood. The Zenovay tracker (≥v2) listens for history.pushState and fires a pageview on every route change, so you don't need to call window.zenovay('trackPageView') manually.
Lazy-loaded sections. Framer's "appear when scrolled into view" pattern doesn't affect the tracker — the script lives in <head> and runs on first paint regardless of section visibility.
Test mode noise. Framer's CMS preview loads pages with a ?framer-publish=true query string. If you want to exclude editor traffic, filter that query string out at the Zenovay dashboard level via saved segments.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Preview shows no data | Custom Code only runs on published site | Click Publish and test the live URL |
| No data on Free plan | Custom Code disabled on Free | Upgrade to Mini or higher |
| Some pages tracked, others not | Per-page Custom Code overriding | Move to site-wide Custom Code |
| Double pageviews | Snippet in site-wide and per-page slot | Pick one scope |
| Events fire but pageviews don't | Tracker version older than v2 (no SPA support) | Re-copy snippet from dashboard |
Privacy & compliance
For cookieless tracking, add data-cookieless="true":
<script defer
data-tracking-code="YOUR_TRACKING_CODE"
data-cookieless="true"
src="https://api.zenovay.com/z.js"></script>
See Privacy Compliance for full details.
Related resources
Need help? Contact [email protected] or visit our Help Center.