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 →Your view, your pace. Changes save here.
OPEN INSTRUMENTS / VERSION 1
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.
A record of what came into view. Never a census of people.
01 / OPEN THE NOTEBOOK
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'
Choose a dataset and world. The button sends one public GET request; the response below is real data.
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
| view | What it answers | Returned records |
|---|---|---|
worlds | How did observed coverage and freshness change? | Hourly or daily world measurements; up to 9,000. |
places | Which servers are in the latest measured directory? | 50 per page; total and page_size included. |
history | What is one server’s recorded trail? | Choose one world and exact host; up to 91 daily points. |
topics | Which title words appear in the sample? | Without word: latest top 100/world. With it: daily history, up to 1,000 records. |
links | Which sampled paths join servers? | At most 250 edges/world on the selected or latest recorded day. |
demand | Which reviewed search words have publishable cells? | Completed-day cells with ≥5 received events; up to 12,000. |
quality | When 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
Supply each parameter once. Unknown parameters, invalid values and repeated parameters return HTTP 400. URL-encode values. All dates and archive windows use UTC.
| Parameter | Allowed values / default | Meaning |
|---|---|---|
view | Seven names above; worlds | Select the dataset. |
world | all, gemini, gopher, spartan, nex; all | One world or all four. Demand selects groups containing this world. |
days | 1, 7, 30, 90, 365, 730; 7 | Lookback window. Only daily world summaries extend past 90 days; demand is at most 30. |
resolution | hour, day; hour | World history only. Windows above 90 days force day. |
host | Lowercase letters, digits, dots, hyphens; ≤253 characters; empty | Substring in directory; exact server for history. Links match source or a protocol-qualified target. |
word | Lowercase ASCII letters; ≤24 characters; empty | Exact sampled word history or published-demand word filter. |
page | Integer 0…999; 0 | Zero-based directory page; 50 records per page. |
order | indexed, changed_24h, fetched_24h, errors, host; indexed | Directory-wide descending metric sort or ascending host name. |
day | Valid YYYY-MM-DD; empty | One 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
{
"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. atat for analysis.statusindexed, distinct, duplicates, unknown_hashesdestinations, known, queuefetched_24h, changed_24h, errorsduplicate_pct, hash_coverage_pct, error_pct, fresh_pctat, world, group, method_version plus defined metrics. Older method 1 observations precede the added reconciliation checks; method 2 records validated collection.at, world, host, group and available count metrics. The JSON metric dictionary defines measures; a field may be absent or null when unavailable.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.at, day, world, source, target, n, group. Source is a host; target includes the destination protocol. Count n is sampled links, not traffic.day, selection, channel, word, outcome, n, at, group. Selections can overlap. Bots and repeats can contribute; do not sum cells into people.at, world, ok, seconds, reason. Failed rounds retain previous measurements. Reasons are bounded public categories.05 / SMALL EXPEDITIONS
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 →Open a directory, choose a host, then request its daily history. Missing observations mean unknown, not disappearance.
Follow gopher.club →Try a title word and compare sample shares with their denominators. Keep the nonrandom sample and English bias in view.
Look for music →Join source and target server addresses to draw a graph. Label it a sample; rotating windows cannot establish network growth.
Trace observed connections →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
| Status | Meaning | Next step |
|---|---|---|
| 200 | Report, possibly empty or truncated | Inspect status, notes, count and truncation. |
| 400 | Invalid filter or oversized report | Correct parameters or narrow the window/world. |
| 503 | Archive busy or temporarily unavailable | Wait 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