Loading tutorials…
Loading tutorials…
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.
Who this is forWebflow site owners (Site or Workspace plan) who need GA4 firing reliably before they spend on ads. Especially relevant if you migrated from a Universal Analytics install and the old gtag is still hanging on somewhere in the project.
What you'll need
Step 1
Custom Code is only available on Site plans (Basic, CMS, Business, Enterprise). The free Starter plan and Workspace-only plans cannot inject GA4.
Open Webflow Designer → top-left logo → Project Settings → Plans.
Confirm the project shows a Site plan (Basic $14/mo, CMS $23/mo, Business $39/mo, or Enterprise). If it says 'Starter — Free,' Custom Code is locked out and GA4 cannot be installed.
Workspace plans (Core, Growth, Agency) cover seats and design features but DO NOT include hosting or Custom Code. A Workspace plan + Free Starter site = no GA4. You need to upgrade the site itself.
If you only need basic page-view tracking and the budget is tight, the Basic plan ($14/mo) is enough. CMS plan is required if you also want to drive dynamic SEO meta tags from a Collection (see the CMS SEO tutorial).
Step 2
In Google Analytics → Admin → Data Streams → Web. The ID starts with G- and is the only thing Webflow needs.
Open analytics.google.com. If you don't have a GA4 property yet, click Admin → Create → Property → Web. Pick a property name, time zone, currency.
Inside the property: Admin → Data Streams → Web → click your stream (or create one for your live custom domain).
Copy the Measurement ID at the top-right — it looks like G-XXXXXXXXXX. This is the only thing you paste into Webflow.
While you are in the data stream settings, click 'Configure tag settings' → 'Show all' → 'Define internal traffic.' Add your own office IP so your testing does not pollute the data. This takes 60 seconds and saves weeks of confused reports later.
Step 3
Webflow Designer → Project Settings → Custom Code → Head Code. Paste the official GA4 gtag snippet with your Measurement ID swapped in.
In Webflow Designer, click the top-left logo → Project Settings (or hit the gear icon on the dashboard project tile).
Open the Custom Code tab. There are two text areas: Head Code and Footer Code. GA4 goes in Head Code.
Paste the standard GA4 snippet (the one Google shows in Admin → Data Streams → Web → Tagging Instructions → Install manually). Replace G-XXXXXXXXXX with your real ID. The snippet is wrapped in a <script> tag — Webflow does not need any modification.
Click Save Changes at the top right of the Custom Code panel. Saving here does NOT publish — Custom Code only goes live after you publish the site.
Hit Publish (top-right of the Designer). Choose your custom domain checkbox AND the webflow.io subdomain (we will filter the staging traffic out in the next step — that is fine).
Wait 30-60 seconds for publish to propagate, then test in the next step.
Step 4
Open your live site in an incognito window. In GA4 → Reports → Realtime, you should appear as 1 user within 30-60 seconds.
Open an incognito/private window (so cached versions of the site do not interfere).
Visit your live custom domain — not the webflow.io URL.
In a separate tab, open GA4 → Reports → Realtime. You should see "Users in last 30 minutes" tick up to 1 within 60 seconds.
Click around 2-3 pages. The 'Views by Page title and screen class' card should show the pages you visited.
If nothing appears after 2 minutes: open the site again, right-click → View Page Source, search for "G-" — your Measurement ID should appear inside a <script> tag in the head. If it does not, the publish did not include Custom Code (most common cause: published to webflow.io subdomain but not custom domain).
Step 5
Every Webflow project has a free staging URL like yoursite.webflow.io. If you do not filter it, GA4 counts staging traffic as production. Add a Data Filter.
In GA4 → Admin → Data Streams → Web → click your stream → Configure tag settings → Show all → Filter unwanted referrals (under advanced).
Actually that filter is for referrals, not subdomains — close it.
The right path: GA4 → Admin → Data Settings → Data Filters → Create Filter → Internal Traffic. But Internal Traffic is IP-based.
For domain-based filtering you need a hostname filter, which GA4 does NOT do natively — you do it inside reports. Create a Custom Report: Explore → Free form → Dimension = Hostname. Add a filter: Hostname exactly matches your custom domain (yourdomain.com). Save the exploration as "Production only."
For ad-hoc reports, set the comparison: Hostname includes "yourdomain" excludes "webflow.io." From now on, run reports through this comparison.
Cleaner long-term fix: publish ONLY to the custom domain (uncheck the webflow.io checkbox in the Publish dialog) for production releases. Use the staging URL only for unpublished design work. This eliminates the noise at the source.
Step 6
GA4 Enhanced Measurement auto-tracks scrolls, outbound clicks, video engagement, file downloads, and form interactions. Most are fine. Form_start fires too aggressively on Webflow forms.
GA4 → Admin → Data Streams → Web → click your stream → toggle Enhanced Measurement to ON if it is off (it is on by default for new streams).
Click the gear icon next to Enhanced Measurement to see the 8 sub-events: Page views, Scrolls, Outbound clicks, Site search, Video engagement, File downloads, Form interactions, Page changes.
Form interactions auto-fires a 'form_start' event the moment a user focuses ANY input on the page. On a Webflow site with a newsletter input in the footer, every page view fires form_start. This skews engagement metrics. Disable Form interactions and use a custom form_submit event instead (covered in the forms tutorial).
Scrolls fires only at 90% page scroll — that is fine for most sites. File downloads fires on PDFs and common file extensions — also fine.
Save the Enhanced Measurement changes. They apply immediately to new traffic.
Step 7
Add a note inside Webflow Project Settings → Custom Code itself (HTML comment) and inside GA4 → Annotations marking install date.
At the top of your Head Code snippet, paste a one-line HTML comment: <!-- GA4 install: G-XXXXXXXXXX — installed YYYY-MM-DD by [your name] — see /docs/analytics --> The comment ships to the browser, which is fine; it is the cheapest documentation that survives team handoffs.
In GA4, there is no built-in annotation tool (Google removed it). Use a shared doc — Notion, Coda, or Webflow CMS — with: install date, Measurement ID, who installed, what events fire, who has Edit access on the GA4 property.
Add yourself plus one backup as Admin on the GA4 property (Admin → Property Access Management). If you are a solo founder, add a personal Gmail as a second Admin so you never get locked out of your own analytics.
If you also use Webflow's native Site Settings → Integrations → Google Analytics field (the legacy one), DELETE the ID from there. It still works but injects a second gtag and double-counts.
Common mistakes
Leaving GA4 in the legacy Site Settings → Integrations field AND in Custom Code
What goes wrong: GA4 fires twice on every page view. Sessions and users inflate by ~2x. Bounce rate and engagement metrics look better than reality. Every ad-spend decision is built on doubled data — usually causes 30-50% over-attribution to Google Ads.
How to avoid: Pick one place: Custom Code (recommended) OR Site Settings → Integrations (legacy, less flexible). Delete the ID from the unused location. Wait 7 days for clean data before trusting reports again.
Not filtering the webflow.io staging subdomain
What goes wrong: Designers, clients, and stakeholders reviewing the staging URL inflate session counts. On a small marketing site, staging can be 30-60% of total traffic in GA4 — making every conversion rate look artificially low and every ad campaign look worse than it is.
How to avoid: Either uncheck the webflow.io publish target after each production release, or create a saved Exploration filtered by Hostname = your-custom-domain.com. Make that the default report you trust.
Pasting the gtag snippet in Footer Code by mistake
What goes wrong: Page views still fire, but anything that expects gtag to exist at body-load time (Meta Pixel hybrid setups, A/B test tools, third-party heatmap pixels) silently breaks. You only find out 6 weeks later when ads attribution does not match GA4.
How to avoid: Move the snippet to Project Settings → Custom Code → Head Code. Publish. Verify in View Source that the script appears inside the <head> tag, not before </body>.
Leaving Enhanced Measurement → Form interactions ON
What goes wrong: Every page with a footer newsletter input fires form_start on every visit. GA4 thinks engagement is sky-high. Audiences built on 'engaged users' are mostly people who never engaged. Remarketing lists drift to junk.
How to avoid: GA4 → Admin → Data Streams → click stream → Enhanced Measurement gear → uncheck Form interactions. Use a custom form_submit event triggered via Webflow's form-submission webhook (covered in the forms tutorial).
Not adding internal traffic IP filters
What goes wrong: You and the design team browsing the site daily account for 5-15% of all traffic on a small site. Engagement metrics, scroll-depth, and time-on-page are all dragged toward 'expert user' values that real visitors never hit.
How to avoid: GA4 → Admin → Data Streams → Configure tag settings → Define internal traffic. Add office IP + every team member home IP. Then Admin → Data Settings → Data Filters → activate the Internal Traffic filter (it ships in Testing mode by default — you must switch it to Active).
Publishing GA4 without testing in Realtime first
What goes wrong: You assume the install worked because Webflow said 'Site published.' Two weeks later, you check reports and they are empty. Now you have lost two weeks of baseline data right before launching ads.
How to avoid: Always open the live custom domain in incognito within 5 minutes of publishing GA4. Confirm 1 user in GA4 → Realtime within 60 seconds. If not, debug immediately rather than 2 weeks later.
Recap
Done — what's next
How to install the Meta Pixel on Webflow (and why you still need CAPI)
Read the next tutorial
Hand it off
GA4 on Webflow is straightforward when nothing else is in the way. It gets messy when the legacy integration field is still active, when a previous developer pasted gtag in three places, or when form tracking needs to talk to HubSpot or Klaviyo at the same time. A vetted Webflow specialist on EverestX wires this up cleanly in 60-90 min — typically $40-80 total at $14-16/hr.
See specialist rates
Custom Code. The Integrations field is a legacy shortcut Webflow kept for backward compatibility — it still works but does not support adding extra config parameters, debug mode, or anything beyond the basic Measurement ID. Custom Code lets you also paste GTM, server-side gtag configs, and consent-mode wrappers when you outgrow basic.
Yes. Custom Code changes are part of the published HTML; saving in the Designer does NOT push them live. Always click Publish (top-right) and select your custom domain. If you only publish to webflow.io, GA4 runs only on the staging URL.
Yes — and for any site running more than 1-2 marketing pixels you should. GTM is one snippet that lets you manage GA4, Meta Pixel, Hotjar, LinkedIn Insight Tag, etc. without re-editing Webflow Custom Code each time. See the 'Install GTM on Webflow' tutorial in this hub.
Three usual culprits: (1) Custom Code is in Footer instead of Head and the ad blocker blocked it before body-render; (2) site was published to webflow.io only, not your custom domain; (3) GA4 has been linked to the wrong Measurement ID (typo in the G-XXXXXXX). View page source, search for 'G-', confirm the ID matches GA4 Admin → Data Streams exactly.
No. The free Starter plan does not allow Custom Code. The cheapest path to GA4 on Webflow is the Basic Site plan at $14/mo (or $12/mo billed annually). Workspace plans alone are not enough.
Webflow has no plugin ecosystem — every tracking install is manual Custom Code. On WordPress, Site Kit or MonsterInsights install GA4 with one click. On Shopify, the GA4 channel in Settings handles it. Webflow rewards design control with more setup work; budget for it.
Webflow
Webflow has no server-side hook, which means the Meta Pixel alone misses 20-40% of conversions on iOS. This walks through the Pixel install AND the three legitimate Conversions API workarounds for Webflow — Zapier, Stape, or HubSpot-as-middleware.
Webflow
GTM is the right move once you are running 2+ marketing pixels. The wrinkle on Webflow: GTM needs both a Head snippet AND a body-open snippet — and Webflow only gives you one body-end slot. Here is the workaround that ships clean.
Webflow
Webflow Forms work great until you realize submissions are going nowhere — notification email mis-configured, no CRM sync, no tracking event fired. This walks the full setup: form, redirect, tracking, and CRM integration.
Webflow
DIY Webflow is great for the first 6 months — the visual editor really is that good. After that, the math usually flips. This is the honest framework: when self-managing costs more than hiring help.