Skip to content

feat: AdSense readiness — content hardening, verification & privacy disclosure - #168

Merged
fatblaine merged 9 commits into
mainfrom
dev
Aug 6, 2026
Merged

fatblaine merged 9 commits into
mainfrom
dev

Conversation

@fatblaine

Copy link
Copy Markdown
Owner

What

Everything needed to apply to Google AdSense. Frontend only.

Content hardening — make the site read as a complete, navigable site with original value, not a pile of template pages:

  • /methodology — original reference page: Residency Shift Index formula & bands, SAL↔SA2 geography, per-dataset sources/years/limits.
  • /suburbs — A–Z index of every suburb (new useAllSuburbs hook over the existing heatmap endpoint), so all ~1494 suburb pages are click-reachable.
  • Per-suburb narrative paragraph — a data-driven "In brief" summary on every suburb card, from a framework-free buildNarrative(); reuses existing hooks so it fires no extra requests.
  • prerender into <body> — seeds each suburb page's #root with that narrative (transpiling narrative.ts for a single source of truth), so a reviewer viewing page source / a non-JS crawler sees real content, not an empty shell.
  • Footer now links About · Methodology · All suburbs · Privacy · Chrome extension; all three new routes added to the sitemap.

Registration & integration:

  • AdSense verification <script> in index.html (publisher ca-pub-5982385876517812) + public/ads.txt.
  • Privacy policy discloses advertising (cookies, opt-out, EEA/UK/CH consent), scoped to the website only — the extension is stated to carry no ads (this page is also the Chrome Web Store policy).

Why

Groundwork before Request review: lower the risk of a Low value content / Difficult site navigation rejection, satisfy ownership verification + the authorised-seller declaration, and make the required ads/cookies disclosure (the old "there is no advertising" wording becomes false once ads run). The /suburbs internal-link hub also helps the current "discovered / 0 indexed" Search Console state.

The narrative text is rule-based, not LLM-generated (bulk LLM generation would itself look like scaled-content abuse); each paragraph's value comes from that suburb's unique ABS data, with wording varied by numeric bands to avoid templated sameness.

Not included (post-approval): the AdSlot component & ad units (§3.5), the CMP consent banner, and tax/payment setup.

How to test

  • cd frontend && npm run build — passes clean.
  • npm run dev → visit /methodology, /suburbs, and a suburb page (check the "In brief" card; a Melbourne suburb includes a crime sentence, Sydney does not). Footer links all resolve.
  • VITE_API_BASE_URL=<api> npm run build:deploy → log reports N suburb pages (M with a seeded narrative); grep '<div id="root">' dist/suburb/<code>.html shows the seeded prose.
  • After deploy: curl -s https://www.suburblensapp.com/ads.txt returns the pub line; a suburb page's source contains adsbygoogle.js?client=ca-pub-5982385876517812; /privacy shows the new Advertising section.

fatblaine and others added 9 commits August 6, 2026 10:52
Two AdSense content-hardening pages (adsense-plan §8.5.3 / §8.5.4):

- /methodology explains the Residency Shift Index formula and bands,
  the SAL/SA2 geography, and each dataset's source, years, and limits.
- /suburbs lists every Sydney/Melbourne suburb A-Z so all ~1494 suburb
  pages are click-reachable, via a new useAllSuburbs hook over the
  existing heatmap endpoint (no new backend).

Both added to the prerendered sitemap and linked from the site footer.
feat: add methodology and all-suburbs index pages
Turn each suburb's "charts + numbers" page into one with human-readable
prose, so the page reads as original content rather than templated filler
(adsense-plan §8.5.1).

A framework-free buildNarrative() assembles up to three paragraphs from
the suburb's real ABS data: the rented-share trend plus the Residency
Shift Index, the community mix (overseas-born share, top origin, top
non-English languages), and the university-qualified share vs the city
benchmark (with crime for Melbourne suburbs only, never fabricated where
it 404s). Verbs and framing switch on numeric bands so suburbs read
differently, not just with the place name swapped.

SuburbNarrative reuses the five hooks SuburbCard already calls, so it
shares the TanStack cache and fires no extra network requests.
feat: add per-suburb editorial narrative paragraph
Previously prerender only swapped <head>, so a reviewer viewing page
source (and any non-JS crawler) saw an empty <div id="root"> — the shell
that reads as Low value content (adsense-plan §8.5.6 step 7).

Prerender now seeds each suburb page's #root with a real data-driven
paragraph. It transpiles src/lib/narrative.ts on the fly via the installed
typescript dep, so the same buildNarrative() the SuburbNarrative component
uses is the single source of truth. Tenure is fetched per suburb through a
concurrency-limited pool (a failed suburb degrades to a head-only page,
never aborts the build).

The seed goes inside #root: main.tsx mounts with createRoot(), which
replaces #root on load, so real users get the full SPA and the prose is
only ever seen pre-hydration or by crawlers — no duplicate content.
feat: prerender suburb narrative into the page body
Once AdSense ads run, the "there is no advertising" statements become
false, and reviewers require an ads + cookies disclosure (adsense-plan
§4). This page is also the Chrome Web Store privacy policy, so all ad
wording is confined to the website and the extension is stated to carry
no ads.

- split the "In short" analytics bullet, add a website-only ads bullet
- new Advertising subsection: AdSense funding, third-party cookies,
  opt-out links, and EEA/UK/CH consent
- add a Google AdSense row to "Who processes your data"
- replace the "we do not sell your data" line with an ads-aware version
- bump the last-updated date
Site is registered in AdSense (publisher ca-pub-5982385876517812) and
needs ownership verification plus an authorised-seller declaration before
requesting review (adsense-plan §3.1 / §3.2).

- add the AdSense loader script to index.html's <head>; prerender uses
  the built index.html as its template, so it propagates to every suburb
  page automatically
- add public/ads.txt so the site declares Google as an authorised seller
  and the account stops warning about unauthorized sellers

Ad units come after approval; this is verification only.
feat: AdSense verification + advertising privacy disclosure
@fatblaine
fatblaine requested a lite review from Copilot August 6, 2026 07:30
@fatblaine fatblaine self-assigned this Aug 6, 2026
@fatblaine fatblaine added documentation Improvements or additions to documentation enhancement New feature or request labels Aug 6, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@fatblaine, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 36 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a4894c86-3daa-4eac-b692-ef5a68c3329b

📥 Commits

Reviewing files that changed from the base of the PR and between e6414e6 and 8edbcb7.

📒 Files selected for processing (12)
  • frontend/index.html
  • frontend/public/ads.txt
  • frontend/scripts/prerender.mjs
  • frontend/src/App.tsx
  • frontend/src/api/suburbs.ts
  • frontend/src/components/Footer.tsx
  • frontend/src/components/SuburbCard.tsx
  • frontend/src/components/SuburbNarrative.tsx
  • frontend/src/lib/narrative.ts
  • frontend/src/pages/BrowsePage.tsx
  • frontend/src/pages/MethodologyPage.tsx
  • frontend/src/pages/PrivacyPage.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@fatblaine
fatblaine merged commit a80a45a into main Aug 6, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants