Configure your analytics
A measurement id firing on your site, data visible in Realtime, and a numeric property id plus read access for anything that reads the property over the API — anacraft included. The first two steps are the dashboard and a paste; the rest is the console work it does not cover.
01Create the property and get the tag
Sign in at app.anacraft.dev with Google, choose Create a new property, and give it your site's URL. It creates the property and the web data stream and hands you the gtag.js snippet with your measurement id already in both of the places it belongs, with a copy button. Nothing to install. The dashboard is part of the Anacrafter Elite plan; the paywall appears before anything is created in your Analytics account, and nothing is charged if you never finish the checkout.
From a terminal, the same thing is one command, on the $2.99 Anacrafter plan (install anacraft first):
$ craft configure yoursite.com
Either way, it creates nothing if the domain already has a property — you get that one's tag instead — so doing it twice is how you get the tag back, not how you end up with two properties splitting your traffic.
The console does the same thing across four screens. This guide does not walk them, because there is nothing to decide in them that the dashboard does not already ask you.
No Google Analytics account yet?
Create one first — that single
step needs Google's terms accepted in a browser, so neither the dashboard nor the command will do it
for you. Everything after it is the dashboard, or craft configure.
02Paste the tag
The dashboard (or craft configure) gives you the snippet with your measurement id
in it. It goes in
<head>, on every page — and only once. A second GA4 config for the
same id double-counts every view. If Google Tag Manager is already on the site, configure GA4 inside
GTM instead of adding the snippet, and remember to publish the container.
Single-page apps need one addition. The snippet fires a pageview on load, and client-side navigation changes the URL without a reload, so every later route goes uncounted until you send it yourself:
// on every route change
gtag('event', 'page_view', {
page_path: location.pathname + location.search,
page_location: location.href,
page_title: document.title,
});
On Next.js, @next/third-parties handles both the placement and the route changes. On
WordPress, Site Kit or any GA4 plugin does; editing header.php works too, but only from a
child theme or the next update erases it.
If your site serves the EEA or UK, set Consent Mode v2 defaults before the tag loads and update them when the visitor chooses. A consent platform emits those calls for you; ordering is the whole game.
Or sidestep the banner entirely with gtag('config', 'G-XXXXXXXXXX', { client_storage: 'none' }).
GA4 then writes no cookie, so there is no device storage to ask consent for. You lose returning-visitor
and multi-day attribution — every visit counts as new — and keep page views, countries, referrers and
Realtime. This site does exactly that, which is why you are reading it without dismissing a banner.
Do not combine the two: an analytics_storage: 'denied' default downgrades every hit to a
consent ping that GA4 reports only through modelling, so a small site sees less data, not more.
03Verify data is arriving
In this order, because each rules out a different failure.
debug_mode: true in the config call.04Change these before you forget
Data retention. Admin → Data collection and modification → Data retention. Event data defaults to 2 months; set 14 months unless policy says otherwise. It governs explorations and funnels rather than the standard reports, and it is not retroactive — data already aged out is gone.
Internal traffic. Admin → Data streams → your stream → Configure tag settings → Define internal traffic, then Admin → Data filters. A new filter is created in Testing, where it does nothing; switch it to Active once you have confirmed it tags your own visits correctly.
Unwanted referrals. Same tag settings menu — add a payment or auth host such as Stripe or PayPal, which would otherwise break session attribution and inflate direct traffic.
Cross-domain measurement belongs there too, if one journey spans two domains. Google Signals, under Data collection, adds demographics and cross-device reporting at the cost of more thresholded rows — an opt-in decision, not a default.
05Key events, and the id that tools want
Key events are what GA4 called conversions before 2024. Mark one at Admin → Events with the Mark as
key event toggle, or create it by name at Admin → Key events if it has not fired yet. For a click or
form submit that enhanced measurement misses, send gtag('event', 'signup_complete') and mark
it once it shows up, which can take a day.
Your property id is at Admin → Property → Property details, top right: a bare number like
397412345. Three ids get confused constantly, and only one of them belongs in an API call.
| Value | Looks like | Belongs in |
|---|---|---|
| Property id | 397412345 | The Data and Admin APIs, and any reporting tool — craft use 397412345 |
| Measurement id | G-XXXXXXXXXX | The on-page tag, and nowhere else |
| Stream id | 1234567890 | Stream-level admin calls only |
06Grant access
Admin → Property access management → +, or Account access management to cover every property at once. Least privilege first:
| Role | Can |
|---|---|
| Viewer | See reports and explorations. The right role for a dashboard or a read-only API client. |
| Analyst | Viewer, plus create and edit shared explorations and audiences. |
| Editor | Analyst, plus edit property settings, streams and events. |
| Administrator | Editor, plus manage users. Keep this to one or two people. |
The No Cost Metrics and No Revenue Metrics restrictions apply on top of the role. People are added by email and see the property on their next sign-in.
07API access, when a tool needs it
Three things have to line up, and each missing one produces its own error.
- A Google Cloud project with both the Google Analytics Data API and Admin API enabled. A tool that fetches reports but cannot list properties has the first on and the second off.
- Credentials: an OAuth client of type Desktop app for a CLI that signs a person in, or a
service account for unattended and server-side use. The read-only scope
analytics.readonlyis enough for anything that only reports. - For a service account, its
…iam.gserviceaccount.comaddress added under Property access management as Viewer. Creating the account grants it nothing by itself, and this is the step people skip.
The Cloud project carries only the API enablement and its own quota — it does not own the Analytics data and need not sit in the same organisation. Running your own project is also how you stop sharing a rate limit with everyone else using the same tool.
Many tools ship their own OAuth client and need none of this. anacraft does:
craft login works with no Google Cloud project at all.
08When it is not working
| Symptom | Usual cause |
|---|---|
| Realtime empty | Tag not in the served HTML, wrong id, or an ad blocker, tracking prevention or CSP dropping the request. Check DevTools → Network for collect. |
| Empty only for you | An active internal-traffic filter is removing exactly the visits you are testing with. |
| Realtime fine, reports empty | The 24–48 hour processing delay, or a date range that excludes today. |
| Every metric doubled | Two GA4 tags on the page — typically gtag.js and GTM both firing. |
| Direct traffic inflated | A payment or auth host counted as a referrer. Add it to unwanted referrals. |
| Explorations missing old data | Data retention still at the 2-month default. |
| API 403 “has not been used” | The Data or Admin API is not enabled on that Cloud project. |
| API 403 permission denied | The account or service account lacks Viewer on that property. |
API 404 on a G- id | Measurement id used where the numeric property id belongs. |
| API 429 | Quota. Poll less often, or move to your own Cloud project. |
09Point anacraft at it
With the property collecting data and your Google account holding at least Viewer on it, three commands connect the dashboard:
# sign in — read + the setup permission, official builds carry their own OAuth client $ craft login # every GA4 property this account can read $ craft props # save one as the default, by numeric property id $ craft use 397412345
Then craft opens the dashboard on real numbers, and craft live is the
fastest confirmation that your tag is still firing. The
quick start covers the rest of the commands.