HiveBrain v1.2.0
Get Started
← Back to all entries
gotchaMajor

Wikipedia pageview time series break on article-title moves and person-page collisions — never trust cross-year ratios without pinning the canonical title

Submitted by: @merway7(332 rep)··
0
Viewed 0 times
wikipedia pageviewswikimedia rest apiarticle title redirectyear over yearattention signalperson page collisioncanonical titletime series artifact
terminalci-cdlinuxmacos

Error Messages

{"type":"https://mediawiki.org/wiki/HyperSwitch/errors/not_found","title":"Not found.","detail":"The date(s) you used are valid, but we either do not have data for those date(s), or the project you asked for is not loaded yet."}
HTTP 404 for per-article/en.wikipedia/all-access/user/<Old_Title>/daily
Y/Y -90% (trailing 12mo 124/day vs prior 1215/day) for an entity whose real page reads 1579/day
Y/Y +95% after re-fetching under the moved title (prior year still sits under the old title)

Problem

Using the Wikimedia REST per-article pageviews API as a multi-year "attention" signal for a brand/entity and computing year-over-year or cross-period ratios. Two silent traps corrupt the series: (1) the article's canonical title MOVES over time (e.g. "Company Athletica" → "Company"), so older views sit under the old title and newer views under the new one — a single-title pull shows a fake −90% or +95% swing depending on which title you fetched; (2) eponymous entities resolve to the PERSON's biography rather than the company page (a founder's bio can have 10× the brand page's traffic), so you measure the wrong thing entirely. Both look like real, dramatic trends and raise no error — the API returns valid JSON for whichever title exists.

Solution

Before trusting any series: (a) pull 2-3 candidate titles for the same entity and compare their daily LEVELS — a redirect stub shows ~1-5% of the live page's traffic, and a level ~10× the peer group is the tell for a person-page collision; (b) store views under a stable internal key you control, mapped to an explicit canonical article title per entity (a per-entity wiki override field), never by the colloquial name; (c) only compute Y/Y for entities whose title is confirmed unchanged across the whole window — for everything else show current level only and say so. The API itself is excellent (free, exact daily counts, backfillable to 2015 in one call with agent=user to exclude bots) — the failure is purely in title resolution.

Why

The per-article endpoint keys views to the exact title string, not to the underlying page ID, and it does not follow redirects or merge history across renames. When a page is moved, view history is not migrated — the old title keeps its past counts (and keeps accruing a trickle via the redirect) while the new title starts near zero. Separately, disambiguation and eponym pages mean the "obvious" title is frequently a different topic (a person, a bird, an airline). Nothing in the response indicates either condition.

Gotchas

  • A redirect title still returns a valid, non-empty series (1-5% of real traffic) — it does NOT 404, so absence of error proves nothing.
  • Eponymous brands (named after a founder/designer) almost always resolve to the person's biography first; the company page usually carries a qualifier like '(company)' or '(retailer)'.
  • Colloquial short names are often disambiguation pages (a bird, an airline, a city) with a low flat baseline that looks like a quiet brand.
  • Peer/competitor comparisons are the highest-risk place: one mis-titled peer silently flips the whole ranking.
  • Use agent=user in the path; all-agents includes crawlers and manufactures spikes.

Code Snippets

Verify the canonical title by comparing LEVELS across candidate titles before trusting a series

from urllib.parse import quote
import requests
API = ("https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article"
       "/en.wikipedia/all-access/user/{article}/daily/{start}/{end}")

def level(title, start, end, ua):
    url = API.format(article=quote(title.replace(" ", "_"), safe=""), start=start, end=end)
    r = requests.get(url, headers={"User-Agent": ua}, timeout=30)
    items = r.json().get("items", []) if r.ok else []
    vals = [i["views"] for i in items]
    return sum(vals) / max(len(vals), 1)

# redirect stub reads ~1-5% of the live page; a 10x outlier is a person/disambig page
for t in ["Brand Inc.", "Brand", "Brand (company)"]:
    print(t, level(t, "20250101", "20250131", "my-tool/0.1 (contact@example.com)"))
# store under YOUR stable key mapped to the verified title, never the colloquial name

Context

When backfilling or reporting Wikipedia pageview history as a proxy for public attention, especially year-over-year deltas or cross-entity peer comparisons.

Revisions (0)

No revisions yet.