The conclusion first: the fourth AdSense rejection on my programmatic OSS directory wasn't about missing E-E-A-T infrastructure. I'd already built the methodology, about, and affiliate-disclosure pages after the third rejection. The fourth rejection happened because of language I'd written intentionally — in a methodology page, in an llms.txt
file, and in author attribution — that signaled low content value to a reviewer even though I'd thought of it as honest.
Fixing it meant re-reading every public-facing text file as if I were a skeptical reviewer, not a developer being transparent about the tools I use.
There's a category of honesty that reads as a warning label to a content reviewer. I had three examples of it.
The first was in the methodology page. To explain the content generation process accurately, I'd written something along the lines of: "The intro text on each page is AI-generated and has not been manually edited." That's factually correct. It's also exactly what a reviewer looking for "low value AI content" would highlight. The intent was transparency; the effect was flagging.
The fix: reframe the same truth in terms of what the page does offer rather than what it lacks. The new version describes how the generation prompt is structured, how the curation gate filters entries, and that the primary citation is the live GitHub repository. It says the same thing about the generation process but leads with the independent data source rather than the editorial gap.
The second was a phrase in the same methodology page: "Do not rely on AI-generated summaries as authoritative sources — verify with the upstream repository." Good advice. But it reads, to a reviewer, as the site itself saying its summaries shouldn't be trusted. Removing it doesn't change what the page is — it removes a self-undermining disclaimer that wasn't doing users any favors either. Anyone clicking a GitHub link is already going to verify.
The third was llms.txt
. I'd included a description of the project as "a 6-month experiment running AI-curated directory sites." Experiment is fine for developer writing. For a site seeking AdSense approval, it frames the content as provisional. I removed it. The factual content of llms.txt
— what the site covers, what data it uses — stayed. The framing as an experiment did not.
Building E-E-A-T transparency pages solved the structural problem. The fourth rejection exposed an attribution gap I'd missed: the pages existed, but "SEO Farm" was listed as the operator rather than a person. The about page said "we" without naming anyone.
AdSense reviewers aren't checking WHOIS records. They're checking whether there's a real person behind the content. Google's Search quality rater guidelines explicitly treat named authorship as a Trust signal under E-E-A-T, and the AdSense review process applies similar heuristics. A named human author with a GitHub link and a contact path satisfies that check in a way "SEO Farm" does not. I updated the about, affiliate-disclosure, and per-alternative editorial takes on all three sites to list a real name.
This wasn't about gaming the review process. The content is built by me. The operator is me. The previous abstraction behind a project name was a holdover from when I thought the brand mattered more than the identity. It doesn't, at this stage.
One change that wasn't about language at all: the minimum number of curated entries required before a category page gets published. The constant in curation.ts
controls it:
export const CATEGORY_MIN_CURATED = 1; // lowered from 2
The original threshold was 2. With 18 curated entries spread across roughly 17 categories, almost every category had exactly one qualifying entry. At threshold 2, only one category page was generated — the site showed "1 categories" in navigation, which looks like an incomplete site.
Lowering the threshold to 1 produced the correct structure: each category gets its own page, the navigation shows a real set of categories, and the site looks finished rather than under construction. Each category page is distinct — it has specific guidance for that SaaS category, a FAQ block, and at minimum one complete comparison — so the threshold change is defensible on content grounds, not just cosmetic.
The connection to AdSense: a site that looks incomplete is more likely to be flagged as thin content even if individual pages are thorough. Structure signals maturity.
Changing the category minimum had a downstream effect I'd partially addressed earlier but needed to revisit. The sitemap filter in astro.config.mjs
needs to match the curation logic in curation.ts
— a single-source-of-truth problem I'd previously solved with explicit code comments:
// ⚠️ KEEP IN SYNC: astro.config.mjs sitemap filter and curation.ts
// must share the same threshold values. If you change one, change both.
When I changed CATEGORY_MIN_CURATED
from 2 to 1, the sitemap filter needed the same change. A category that's indexed but not in the sitemap doesn't help; a category that's in the sitemap but doesn't get built is a 404. Both are bad signals.
The broader lesson here connects to what I wrote about noindex gates for programmatic pages: the indexing decision and the sitemap inclusion need to be in sync, and having that sync enforced by a shared constant — rather than duplicated magic numbers — makes the relationship auditable.
Looking at the complete diff from the fix commit:
The changes that took longest: the methodology rewrites. The word-level edits needed the most iteration because removing a phrase while keeping the surrounding argument coherent is harder than adding new content.
Whether this submission succeeds. The fourth rejection was seven days ago as of this writing, and re-submissions take time.
What I do know: each rejection gave me a more specific diagnostic. Rejection one was about the .vercel.app
domain — AdSense doesn't approve subdomain hostnames. Rejection two was about thin content without curation. Rejection three was about missing E-E-A-T infrastructure. Rejection four was about language that reads as self-undermining even when it's accurate.
The pattern across all four: reviewers see a different signal set than developers do. Developers read methodology pages as technical documentation. Reviewers read them as quality assessments. Those two readings produce different sentences.
This only applies to manual review phases. Once a site has AdSense approval and is relying on algorithmic quality evaluation, the language in a methodology page probably doesn't matter much. The programmatic quality signals — curation depth, data freshness, internal linking, structured data — matter more at scale.
But at the approval stage, the reviewer is a person, and human reviewers read sentences. The sentence-level review of every public-facing page that a reviewer might land on — not just the main content pages — is worth doing once before submission.
Does removing "don't trust AI summaries" make the site less honest?
The underlying advice (check the GitHub link) is still expressed by making the GitHub link prominent on every alternative card. Removing the disclaimer doesn't change the user experience — it removes a statement that was doing negative work.
Why not just add more manually edited content?
The three-tier content quality approach handles this at the pipeline level. Manual editing doesn't scale; the curation gate is the quality filter. Adding hand-edited paragraphs on 18 pages is feasible, but it's a different lever than fixing the implicit signals.
What does llms.txt have to do with AdSense?
llms.txt
is a public file, indexed by crawlers, that describes the site for LLM consumers. Whether AdSense reviewers actually read it is unknown, but it's a public-facing file that contains the description I'm choosing to broadcast. Framing the site as an "experiment" in a public file is the same as framing it as an experiment anywhere else.
Should every programmatic site do a language audit before AdSense submission?
Yes. Read every page that a reviewer landing on the homepage might navigate to within two clicks. Read it as an outsider. The question to ask at each paragraph is: does this sentence explain what value the page offers, or does it explain what value the page lacks?
What's the category minimum you'd recommend for a new site?
Start at 1. Add a minimum only when you have enough content that a category with 1 entry looks sparse relative to categories with 5+. Premature thresholds hide content you actually have.
Part of an ongoing 6-month experiment running three AI-curated directory sites. The technical claims here are real; this article was AI-assisted.