Skip to main content
6 min read

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

StepWhereWhat you do
1Zenovay dashboardCopy your tracking snippet
2Framer → Site Settings → General → Custom CodePaste it into Start of <head> tag
3PublishClick Publish in the top-right corner
4Zenovay dashboardReal-time visitors appear within ~30 seconds

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

  1. Open your project in Framer.
  2. Click Site Settings (gear icon at the top of the left panel).
  3. Open the General tab if it isn't already.
  4. Scroll to Custom Code.
  5. In Start of <head> tag, paste:
<script defer data-tracking-code="YOUR_TRACKING_CODE" src="https://api.zenovay.com/z.js"></script>
  1. Click outside the field to save automatically.
  2. 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:

  1. Select the page in the Pages panel.
  2. Open the page's right-side panel and scroll to Custom Code.
  3. Paste the snippet into Start of <head> tag for that page.
  4. 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

PlanCustom CodeCustom 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

SymptomLikely causeFix
Preview shows no dataCustom Code only runs on published siteClick Publish and test the live URL
No data on Free planCustom Code disabled on FreeUpgrade to Mini or higher
Some pages tracked, others notPer-page Custom Code overridingMove to site-wide Custom Code
Double pageviewsSnippet in site-wide and per-page slotPick one scope
Events fire but pageviews don'tTracker 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.



Need help? Contact [email protected] or visit our Help Center.

Was this page helpful?