Loading tutorials…
Loading tutorials…
Framer doesn't have a native GA4 field — every install goes through Custom Code. Half of DIY Framer GA4 installs end up double-counting from the .framer.app staging subdomain or missing form-submit events entirely. This walks the full install.
Who this is forFramer site owners who need GA4 reliable before they start paid ads, do SEO measurement, or report to investors. Especially relevant if you've never set up GA4 on a Framer site before.
What you'll need
Step 1
analytics.google.com → Admin → Create Property → Web. The Measurement ID (G-XXXXXXXXXX) is all Framer needs.
Open analytics.google.com. If you don't have a GA4 property yet, click Admin → Create → Property → Web. Pick property name, time zone, currency.
Inside the property: Admin → Data Streams → Web → click your stream (or create one for your custom domain).
Copy the Measurement ID at the top-right — looks like G-XXXXXXXXXX. This is the only thing you paste into Framer.
While in the data stream settings, click 'Configure tag settings' → 'Show all' → 'Define internal traffic.' Add your office IP so internal testing doesn't pollute data.
Also in tag settings: enable Enhanced Measurement (it captures scrolls, outbound clicks, file downloads automatically). Most teams want this on.
Step 2
Project settings → Site → Custom Code → Head start. Paste the GA4 gtag snippet with your Measurement ID.
In Framer, open Project settings (top-left menu) → Site → Custom Code.
Two sections: "Head start" (runs early on every page) and "Body end" (runs after page loads). GA4 goes in Head start.
Paste the standard GA4 snippet from Google's install instructions. Replace G-XXXXXXXXXX with your real Measurement ID.
Standard snippet looks like: <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-XXXXXXXXXX'); </script>
Click Save Changes. Publish the project — Custom Code only goes live after publish.
Step 3
Framer publishes to both your custom domain AND a .framer.app URL. Without a filter, you double-count.
In GA4 → Admin → Data Streams → click your Web stream.
Scroll to "Configure tag settings" → "Show all" → "Add modification."
Choose "Filter event by parameter." Set: page_location contains ".framer.app" → set traffic source to "internal" OR drop the event.
Alternative (simpler): in Framer Project settings → SEO, set "Discourage search engines" ON for the staging URL. Then in GA4 → Admin → Data Settings → Data Filters → create an "Internal Traffic" filter referencing the staging hostname.
Verify by visiting your .framer.app URL: events should be filtered/marked as internal in DebugView.
Step 4
Open the live custom domain in incognito. Realtime users should tick up within 60 seconds.
Open an incognito/private window. Visit your live custom domain (NOT the .framer.app URL).
Open GA4 → Reports → Realtime in another tab. "Users in last 30 minutes" should tick up to 1 within 60 seconds.
Click around 2-3 pages on the live site. "Views by Page title" should show the pages you visited.
If nothing appears after 2 minutes: View Page Source on your site, search for "G-" — your Measurement ID should be there. If not, the Custom Code didn't publish (check that you saved in Project settings AND clicked Publish on the project).
Step 5
Framer forms don't auto-fire GA4 events. Add a Custom Code listener or use Framer's form-submit webhook to push events.
Option A (easier, less precise): Use Enhanced Measurement's "Form interactions" — turn on in GA4 Data Stream settings. Captures form starts and submits automatically, but the parsing is best-effort.
Option B (more reliable): Set up a "thank-you page" — after form submit, Framer redirects to /thank-you. Then in GA4, create a custom event for page_view where page_location = /thank-you. Mark as Key Event.
Option C (most precise): Custom Code in Body end with a form-submit listener that calls gtag('event', 'generate_lead', {...}). Requires JavaScript chops.
For most marketing sites, Option B is the right balance. Build a thank-you page in Framer, redirect form on submit, track the thank-you page view as a conversion.
Step 6
GA4 → Admin → Events → mark the key event. Set up Google Ads import if running paid ads.
Wait 24 hours after first conversion fires.
GA4 → Admin → Events. Find your conversion event (e.g., thank_you_view or generate_lead).
Toggle "Mark as Key Event" ON. This is what makes the event visible to Google Ads, A4 conversion reports, and attribution.
If you run Google Ads: GA4 → Admin → Product Links → Google Ads links → link. Then in Google Ads → Goals → Conversions → Import the GA4 key event.
Set attribution model in GA4 → Admin → Attribution settings. Default is data-driven (good for most). Override only if your business model demands it.
Common mistakes
Double-counting from the .framer.app subdomain
What goes wrong: Both your custom domain and .framer.app fire GA4 events. Sessions inflated 30-50%. Ad ROAS reports lie. Bid strategies optimize against bad data.
How to avoid: Filter the staging hostname in GA4 OR set "Discourage search engines" on staging in Framer SEO settings.
GA4 in Body end instead of Head start
What goes wrong: GA4 loads after the page renders. First-page-view events fire late and sometimes get lost. Bounce rate looks artificially low. Some third-party vendors (Meta Pixel) fail to find gtag.
How to avoid: Move GA4 snippet to Head start in Framer Project settings → Custom Code.
No form-submit tracking
What goes wrong: You can see traffic to the site but not whether forms convert. Can't measure ad ROI. Can't optimize landing pages. Critical funnel metric missing.
How to avoid: Either turn on Enhanced Measurement form interactions OR build a thank-you page and track the page view as a conversion.
Not marking events as Key Events
What goes wrong: Events fire in GA4 but don't appear in Google Ads import dialog. Conversion column in GA4 stays empty. Bid strategies have no signal.
How to avoid: GA4 → Admin → Events → toggle "Mark as Key Event" for your conversion event. Wait 24 hours, then re-check.
No internal traffic filter
What goes wrong: Your own visits, your team's visits, agency visits all pollute the data. A 50-user team with active site visits inflates session counts 20-40% on a small site.
How to avoid: GA4 → Admin → Data Stream → Configure tag settings → Define internal traffic. Add office IP range. Filter Internal Traffic in Data Filters.
Recap
Done — what's next
How to set up a Framer site end-to-end
Read the next tutorial
Hand it off
GA4 install is mechanical setup. GA4 reporting that drives decisions (conversion paths, attribution modeling, audience segmentation) is craft. A specialist who installs GA4 + builds the reporting + maintains it as the site evolves typically runs $200-500/mo at $14-16/hr.
See specialist rates
For a single-channel marketing site, direct gtag is simpler — paste into Custom Code, done. For a stack with multiple pixels (GA4 + Meta + LinkedIn + Hotjar), GTM is worth the setup. Lets you manage all tags in one place. For most Framer sites with under 3 pixels, skip GTM.
Framer has native integrations for Plausible and Fathom (privacy-friendly analytics) — toggle on in Project settings. Use these if you only need page views and don't need Google Ads conversion import. Use GA4 if you run Google Ads or need detailed funnel/attribution analysis.
Page views: data is reliable within 24 hours of setup. Conversions: wait 7-14 days minimum after the first event fires — GA4's attribution model needs sample size. Don't make bid strategy changes off the first 3-7 days of conversion data.
Yes — same path: Project settings → Custom Code → Head start. Paste each pixel's snippet. With 3+ pixels, switch to Google Tag Manager (paste GTM container in Custom Code, manage all pixels inside GTM).
Three usual culprits: (1) GA4 attribution is data-driven and counts conversion-influencing sessions, CRM counts only the form-submit moment; (2) GA4 has sampling on high-traffic sites; (3) Ad blockers and iOS ITP strip GA4 events but don't strip form submissions. Expect 5-15% gap; if larger, investigate.
Framer
Framer feels like Figma until you hit publish — then it suddenly behaves like a real CMS. This walks the path from empty project to a live custom domain, including the breakpoint and domain-connect steps that trip up most first-time builders.
Framer
Framer's native form is easy to design and easy to misconfigure. Most DIY setups capture leads to the Framer CMS and never route them to email, CRM, or Slack — so leads pile up in a dashboard nobody checks. This walks the full integration path.
Framer
Framer ships clean HTML and fast Core Web Vitals — but it does not auto-generate good SEO meta. Every page needs deliberate title, description, OG, and (for CMS) dynamic bindings. This is the full setup specialists run on every Framer site.
Framer
Framer is gorgeous and accessible — until you hit the wall where every change costs you a day. This is the honest framework: when the time cost of DIY exceeds the cost of hiring, and how to tell which side you're on.
Webflow
Webflow doesn't have a native GA4 field anymore — every install goes through Custom Code. Most DIY setups end up double-counting from the webflow.io staging subdomain or missing events from form submits. This walks the install + the filters that fix both.