senternet-site-ahrefs-web-analytics
Add Ahrefs Web Analytics with build-time env gating and lazy loading, as an alternative or addition to Google Analytics.
Files1
View on GitHubSKILL.md.claude/skills/senternet-site-ahrefs-web-analytics/SKILL.md
GitHubAhrefs Web Analytics Setup
Add Ahrefs Web Analytics to a Vite + React site with lazy loading, environment gating, and no render-blocking. Ahrefs Web Analytics is a free, privacy-friendly, cookieless visitor-tracking snippet, so there is no cookie banner and no consent gate to wire up. Use it as an alternative to Google Analytics, or alongside it — the two don't conflict.
This is Ahrefs Web Analytics (a first-party visitor-tracking snippet you embed on the site). It is not the Ahrefs Site Audit / API work covered by /senternet-site-ahrefs-audit, and it does not need the Ahrefs MCP server.
Prerequisites
None beyond an Ahrefs account. Unlike GA4, there is no Firebase Console linking and no gcloud or Analytics Admin API step — Ahrefs Web Analytics is independent of Firebase and Google.
Design principles
- The snippet loads after
window.loadso it never blocks FCP or LCP - The tracking key is injected at build time via a Vite plugin so dev builds are analytics-free
- The block is stripped entirely in dev/staging — it never loads on non-prod environments
- All pageviews (including bounces) are tracked because the script loads on every visit, not on interaction
Steps
1. Get the Ahrefs Web Analytics tracking key
The only value this skill needs is the data-key. Its shape is a UUID: 36 characters, lowercase hex in the 8-4-4-4-12 groupings, e.g. a1b2c3d4-5678-90ab-cdef-1234567890ab (regex [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}). Treat that pattern as a sanity check, not a hard gate — if a supplied value looks close but doesn't match exactly, confirm it with the user rather than rejecting it.
If the user supplied the key when invoking this command, use it directly and skip the dashboard steps. Accept either form and extract the key without asking again:
- a bare key:
a1b2c3d4-5678-90ab-cdef-1234567890ab - the whole install snippet pasted in — pull the value out of
data-key="...".
Only when no key was supplied, retrieve it from Ahrefs:
- Sign in to the Ahrefs dashboard and open Web Analytics.
- Add the website/project for this site's domain.
- Ahrefs generates an install snippet of the form:
<script src="https://analytics.ahrefs.com/analytics.js" data-key="YOUR_KEY" async></script> - Copy the
data-keyvalue.
2. Add the Ahrefs block to index.html
Insert between comment markers so the Vite plugin can substitute or strip it:
<!-- AHREFS_START -->
<script>
window.addEventListener('load', function() {
if (document.querySelector('script[src*="analytics.ahrefs.com/analytics.js"]')) return;
var s = document.createElement('script');
s.src = 'https://analytics.ahrefs.com/analytics.js';
s.setAttribute('data-key', 'AHREFS_ANALYTICS_KEY');
s.async = true;
document.head.appendChild(s);
});
</script>
<!-- AHREFS_END -->
The literal string AHREFS_ANALYTICS_KEY is replaced at build time by the Vite plugin below.
3. Extend the htmlPlugin in vite.config.ts
Mirror the existing GA branch: when the key is set, substitute the placeholder and unwrap the markers; when it is empty, strip the whole block. If the site already has the GA htmlPlugin, add the Ahrefs handling alongside it rather than creating a second plugin.
const htmlPlugin = (gaId: string, ahrefsKey: string): Plugin => ({
name: 'html-transform',
transformIndexHtml(html) {
// ... existing GA handling ...
if (ahrefsKey) {
html = html
.replace(/AHREFS_ANALYTICS_KEY/g, ahrefsKey)
.replace(/\s*<!-- AHREFS_START -->\n/, '\n <!-- Ahrefs Web Analytics -->\n')
.replace(/\n\s*<!-- AHREFS_END -->/, '');
} else {
html = html.replace(/[ \t]*<!-- AHREFS_START -->[\s\S]*?<!-- AHREFS_END -->\n?/g, '');
}
return html;
},
});
Pass env.VITE_AHREFS_ANALYTICS_KEY into the plugin the same way the Measurement ID is passed.
4. Set VITE_AHREFS_ANALYTICS_KEY in env files
# .env.development — Ahrefs Web Analytics disabled in dev
VITE_AHREFS_ANALYTICS_KEY=
# .env.production — use the data-key retrieved above
VITE_AHREFS_ANALYTICS_KEY=your-ahrefs-key
5. Wire the production key into CI if the site deploys via GitHub Actions
.env.production is not committed, so a CI build has no key unless one is supplied through GitHub Actions. Check whether the repo has a deploy workflow that runs the production build:
ls .github/workflows/ # look for deploy.yml (the canonical Senternet site-deploy workflow)
grep -rl 'deploy:prod\|vite build' .github/workflows/ 2>/dev/null
If no deploy workflow exists, skip this step — the local .env.production value is enough. If one does exist, two edits are required (both, or the CI build silently strips the block and ships analytics-free HTML):
Reference the secret in the workflow. Add
VITE_AHREFS_ANALYTICS_KEYto the build step'senv:block, alongside the otherVITE_*values, in.github/workflows/deploy.yml:env: VITE_BASE_URL: ${{ secrets.VITE_BASE_URL }} VITE_GA_ID: ${{ secrets.VITE_GA_ID }} VITE_AHREFS_ANALYTICS_KEY: ${{ secrets.VITE_AHREFS_ANALYTICS_KEY }}Create the repo secret with the same value as
.env.production(skip ifgh secret listalready shows it):REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) gh secret set VITE_AHREFS_ANALYTICS_KEY --repo "$REPO" --body "your-ahrefs-key" gh secret list --repo "$REPO" # confirm VITE_AHREFS_ANALYTICS_KEY is present
The secret name must match the env var name exactly. The value is the same Ahrefs data-key you put in .env.production — it is a public site identifier, not a credential, but it lives in secrets so the workflow's env: mapping stays uniform with the other VITE_* keys.
6. Strip the Ahrefs script from prerendered HTML
In scripts/prerender.mjs, strip the Ahrefs <script> tag so it isn't double-loaded when the hydrated app adds it (mirror the GA prerender-strip):
html = html.replace(
/<script[^>]*src="https:\/\/analytics\.ahrefs\.com\/analytics\.js[^"]*"[^>]*><\/script>/g,
''
);
7. Allowlist analytics.ahrefs.com in the CSP
If the site has a Content Security Policy (from /senternet-site-csp), the default script-src 'self' blocks the Ahrefs script from loading and connect-src 'self' blocks it from beaconing data back. Extend the policy in firebase.json:
script-src → add: https://analytics.ahrefs.com
connect-src → add: https://analytics.ahrefs.com
If the site has no CSP yet, skip this — /senternet-site-csp already knows to include Ahrefs Web Analytics when it generates the policy. After editing the CSP, confirm in DevTools that there are no CSP violation errors for analytics.ahrefs.com in the console.
Verification
After deploying to production:
- Open Chrome DevTools → Network tab
- Filter by
analytics.ahrefs.com - Confirm the script loads after the page
loadevent fires, not during initial HTML parse - Check the Ahrefs Web Analytics dashboard to confirm visits are arriving
Framework: Next.js track
No index.html and no htmlPlugin on this track. Load the analytics script with next/script from app/layout.tsx, gated on the env var:
import Script from 'next/script';
const ahrefsKey = process.env.NEXT_PUBLIC_AHREFS_KEY;
{ahrefsKey && (
<Script src="https://analytics.ahrefs.com/analytics.js" data-key={ahrefsKey} strategy="lazyOnload" />
)}
NEXT_PUBLIC_AHREFS_KEYreplaces theVITE_*name, and must also be listed inapphosting.yamlwithBUILDavailability.strategy="lazyOnload"gives the same off-the-critical-path loading the Vite track gets from itsload-event deferral.- Leave the key empty in
.env.developmentso local traffic never reports. - No prerender strip step is needed.
See /senternet-site-framework for the full convention map.