Display
Make yourself at home
Text100%
Graphics100%

Your view, your pace. Changes save here.

OPEN INSTRUMENTS / VERSION 1

A field guide to
four little worlds

Bring a question. Borrow an instrument. Take the observations home.

The public observatory API returns measured histories, server details, title-word samples, sampled connections and collection quality for Gemini, Gopher, Spartan and Nex. No account or API key is needed.

FROM A WORLD TO YOUR NOTEBOOK
  1. Four worldsObserved indexesGemini · Gopher
    Spartan · Nex
  2. The archiveValidated roundsBounded readings,
    recorded through time
  3. Public APIBounded reportsChoose a world.
    Follow a variable.
  4. Your notebookCharts & questionsExplore, compare,
    take the data home.

A record of what came into view. Never a census of people.

01 / OPEN THE NOTEBOOK

Your first reading

Send a GET request to https://braigetori.org/api/observatory. The default is seven days of hourly observations for all four worlds. The archive began September 12, 2026; choosing a longer window does not create earlier measurements.

curl --fail --get 'https://braigetori.org/api/observatory' \
  --data-urlencode 'view=worlds' \
  --data-urlencode 'world=all' \
  --data-urlencode 'days=7'

Take a live reading

Choose a dataset and world. The button sends one public GET request; the response below is real data.

Open this JSON report ·

Ready when you are.

Choose “Take a reading” to query the public archive.

Preview shows at most three records. Open the JSON link for the entire bounded report.

02 / PICK AN INSTRUMENT

Seven datasets, different questions

viewWhat it answersReturned records
worldsHow did observed coverage and freshness change?Hourly or daily world measurements; up to 9,000.
placesWhich servers are in the latest measured directory?50 per page; total and page_size included.
historyWhat is one server’s recorded trail?Choose one world and exact host; up to 91 daily points.
topicsWhich title words appear in the sample?Without word: latest top 100/world. With it: daily history, up to 1,000 records.
linksWhich sampled paths join servers?At most 250 edges/world on the selected or latest recorded day.
demandWhich reviewed search words have publishable cells?Completed-day cells with ≥5 received events; up to 12,000.
qualityWhen did collection succeed or fail?Most recent 500 attempts, including validation and read duration.

Always inspect truncated. A limit is a limit, not evidence that the underlying world has no more records. Directory paging is the way to retrieve the full latest server directory.

03 / TURN THE DIALS

The query vocabulary

Supply each parameter once. Unknown parameters, invalid values and repeated parameters return HTTP 400. URL-encode values. All dates and archive windows use UTC.

ParameterAllowed values / defaultMeaning
viewSeven names above; worldsSelect the dataset.
worldall, gemini, gopher, spartan, nex; allOne world or all four. Demand selects groups containing this world.
days1, 7, 30, 90, 365, 730; 7Lookback window. Only daily world summaries extend past 90 days; demand is at most 30.
resolutionhour, day; hourWorld history only. Windows above 90 days force day.
hostLowercase letters, digits, dots, hyphens; ≤253 characters; emptySubstring in directory; exact server for history. Links match source or a protocol-qualified target.
wordLowercase ASCII letters; ≤24 characters; emptyExact sampled word history or published-demand word filter.
pageInteger 0…999; 0Zero-based directory page; 50 records per page.
orderindexed, changed_24h, fetched_24h, errors, host; indexedDirectory-wide descending metric sort or ascending host name.
dayValid YYYY-MM-DD; emptyOne link-sample day. Empty selects the latest recorded day in the window.

Parameters outside their dataset’s scope have no effect. For example, resolution does not turn daily server history into hourly history. A history request requires both an exact host and a single world.

04 / READ THE MARKINGS

Response anatomy

{
  "version": 1,
  "generated": 1789225200,
  "filters": {"view": "worlds", "world": "all", "days": 7, "…": "…"},
  "status": {"last_success": 1789224900, "failed_worlds": [], "…": "…"},
  "metrics": {"indexed": ["Indexed URLs", "Definition…"], "…": "…"},
  "rows": [{"at": 1789224900, "world": "gemini", "indexed": 1234, "…": "…"}],
  "count": 1,
  "truncated": false,
  "retention": {"hourly_days": 90, "daily_world_days": 730, "…": "…"},
  "notes": ["Dataset-specific methods and limitations…"]
}

Illustrative, abbreviated structure above; 1,234 is an example, not a live count. The live reader shows actual values.

generated vs. at
Unix seconds: report generation time versus observation time. Cached reports can have an older generation time. Use row at for analysis.
status
Last attempt/success, failed worlds, synthetic marker, daily store-check time and outcome. A null integrity outcome means unknown. Latest successful data can remain available after a failed round.
indexed, distinct, duplicates, unknown_hashes
Searchable URL count; distinct known content hashes within a world; additional copies of those hashes; URLs without hashes. The last three reconcile to indexed URLs. They are not counts of authors.
destinations, known, queue
Indexed server addresses; known resources including unindexed ones; pending Gemini queue entries or due resources in other worlds. Queue populations differ across protocols.
fetched_24h, changed_24h, errors
Resources successfully fetched within 24 hours; indexed resources whose last observed content change falls in 24 hours; known resources currently carrying a failure. These are not visit counts or publication dates.
duplicate_pct, hash_coverage_pct, error_pct, fresh_pct
Duplicate/indexed, known-hash/indexed, failures/known and fetched/known percentages. A zero denominator yields null, not zero.
World rows
at, world, group, method_version plus defined metrics. Older method 1 observations precede the added reconciliation checks; method 2 records validated collection.
Server rows
at, world, host, group and available count metrics. The JSON metric dictionary defines measures; a field may be absent or null when unavailable.
Topic rows
at, day, world, word, n, sample, rate, group. Count n is title-document occurrences; sample is the sampled title denominator; rate is 100 × n/sample.
Link rows
at, day, world, source, target, n, group. Source is a host; target includes the destination protocol. Count n is sampled links, not traffic.
Demand rows
day, selection, channel, word, outcome, n, at, group. Selections can overlap. Bots and repeats can contribute; do not sum cells into people.
Quality rows
at, world, ok, seconds, reason. Failed rounds retain previous measurements. Reasons are bounded public categories.

05 / SMALL EXPEDITIONS

Questions worth taking outside

Copies & originals

Compare indexed URLs, distinct hashes and duplicate share over time. Separate improved crawl coverage from changes in the underlying community.

Read 90-day world histories →

Follow a familiar server

Open a directory, choose a host, then request its daily history. Missing observations mean unknown, not disappearance.

Follow gopher.club →

Words across worlds

Try a title word and compare sample shares with their denominators. Keep the nonrandom sample and English bias in view.

Look for music →

A sampled constellation

Join source and target server addresses to draw a graph. Label it a sample; rotating windows cannot establish network growth.

Trace observed connections →

Download a full server directory with Python

This standard-library example reads all pages and checks their collection round and keys. If collection changes during paging, start again after the round completes.

import json
from urllib.parse import urlencode
from urllib.request import urlopen

base = "https://braigetori.org/api/observatory?"
rows, rounds, totals = [], set(), set()
for page in range(1000):
    query = urlencode(dict(view="places", order="host", page=page))
    with urlopen(base + query, timeout=20) as response:
        report = json.load(response)
    rows.extend(report["rows"])
    rounds.add(report["status"]["last_success"])
    totals.add(report["total"])
    if len(rows) >= report["total"]:
        break
assert len(rounds) == len(totals) == 1, "Collection changed; retry"
assert len({(r["world"], r["host"]) for r in rows}) == len(rows)
assert len(rows) == totals.pop(), "Directory incomplete"
with open("braigetori-servers.json", "w") as output:
    json.dump(rows, output, indent=2)

For analysis, join on world and observation time, preserve missing values, and inspect collection gaps before calculating differences. The observatory laboratory offers regression, Pearson/Spearman correlation, smoothing and exports. Fits describe the observations; they do not establish causation or predict community growth.

06 / KNOW YOUR INSTRUMENT

Limits that belong beside the data

StatusMeaningNext step
200Report, possibly empty or truncatedInspect status, notes, count and truncation.
400Invalid filter or oversized reportCorrect parameters or narrow the window/world.
503Archive busy or temporarily unavailableWait and retry with backoff; never treat failure as zero.

The endpoint supports public GET reports, not arbitrary SQL or administrative commands. Browser access is same-origin; no cross-origin browser permission is promised. Scripts and notebooks can use ordinary HTTPS. Save the returned filters, metric definitions and notes alongside your rows so the evidence stays interpretable.

Privacy policy · Return to the instruments · Questions / corrections