Feeds and data
Every sign on Road Sign Math is open to read. Follow new signs in a feed reader, or build something with them: a map, a quiz, a bot, a mashup. No key, no sign-up.
- Feeds
/feed.xmlNew signs, Atom and JSON Feed - Every sign
/signs.jsonNumbers, ways, places, finders, photos - Players
/players.jsonCounts, states, signs and badges - On a map
/signs.geojsonA point for every sign - The API
/api/v1Public JSON reads, OpenAPI - For agents
/llms.txtThe site in words, for AI tools
Feeds
The newest 50 signs, each with its photos, the math, who found it, when and where, and any other ways to make it true. Paste the address into any feed reader.
- Atom: https://roadsignmath.xyz/feed.xml
- JSON Feed 1.1: https://roadsignmath.xyz/feed.json
- One player’s signs:
/players/<handle>/feed.xmlandfeed.json, linked from each player’s page.
A sign’s item is dated when it was posted and updated when someone adds a way. Readers find the feeds on their own from any page here.
Every sign
https://roadsignmath.xyz/signs.json has every sign on the map, newest posted first, with everything its page shows. It opens from any web page: it is served with Access-Control-Allow-Origin: *.
const res = await fetch('https://roadsignmath.xyz/signs.json');
const { signs } = await res.json();
for (const sign of signs) {
console.log(sign.title, sign.ways[0]?.text ?? 'not solved yet');
}The file
Each of the three files starts with the same fields, then its list: signs, players or features.
| Field | What it is |
|---|---|
versionnumber | The file’s format, now 1. New fields can appear without it changing; it goes up if a field is renamed, removed or changes meaning. |
titlestring | The file’s name. |
descriptionstring | What is in it. |
home_page_urlstring | The site. |
urlstring | The file itself. |
docs_urlstring | This page. |
license.namestring | The licence for everything in the file, photos too: CC BY 4.0. |
license.urlstring | The licence’s text. |
license.creditstring | How to give credit. |
updatedstring or null | The newest change to any sign: a post or a way, as a UTC time. |
counts.signsnumber | Shown signs. |
counts.playersnumber | Players with a page: a name, and a sign or a badge on the map. |
counts.statesnumber | US states with a sign. |
counts.waysnumber | Ways to make the signs true, on all of them. |
A sign
| Field | What it is |
|---|---|
idstring | The sign’s id. Never changes. |
slugstring | Its name in its address, /signs/<slug>. Never changes. |
urlstring | Its page. |
titlestring | Its title, as the poster wrote it. |
captionstring or null | What the poster wrote about it. |
found_onstring | The day it was found, YYYY-MM-DD, in the finder’s own time. A day, not a moment. |
posted_atstring | When it was posted, as a UTC time. |
updated_atstring | When it last changed: when it was posted, or its newest way. |
posted_bystring or null | The handle of the player who posted it. |
place.labelstring | Where it was, in words: “I-35W northbound, Bloomington, Minnesota”. |
place.statestring or null | The two-letter US state, when known. |
place.latnumber or null | Latitude. Null when nobody knows where it was. |
place.lngnumber or null | Longitude. Null when nobody knows where it was. |
place.approximateboolean | True when the point is only as good as a town or a state. Most are. |
numbers[].valuestring | A number on the sign as a plain decimal: “90”, “1.5”. |
numbers[].textstring or null | What it was read from: “90th St”, “EXIT 7B”. |
numbers[].whystring or null | Why the value differs from the text: “Letters dropped”. |
numbers[].boxarray or null | Where it is on the first photo, [x, y, width, height] as fractions of the photo, from the top left. |
finders[].namestring | Who found it. |
finders[].handlestring or null | Their handle, when they play. Null for someone named who doesn’t. |
finders[].urlstring or null | Their page, when they have one. |
finders[].rolestring | found, took_photo or spotted. |
way_countnumber | How many ways there are. |
ways[].textstring | The math as plain text, as the app’s checker writes it: “√(5 − 1) = 2”. |
ways[].texstring or null | The same math as LaTeX, as the site draws it (÷ is a stacked fraction). |
ways[].valuestring | What both sides come to. |
ways[].numbersarray of strings | The sign’s numbers the way used, in reading order. |
ways[].byobject or null | Who found the way: handle, name and url (their page, or null). |
ways[].created_atstring | When it was added, as a UTC time. Ways are oldest first; the first is the one on the sign’s plate. |
photos[].idstring | The photo’s id. Never changes. |
photos[].widthnumber | Its width in pixels, at the large size. |
photos[].heightnumber | Its height in pixels, at the large size. |
photos[].altstring | What the photo shows, in words. |
photos[].urlstring | The photo, 1600 pixels on the long side, as a JPEG with no camera details or location. |
photos[].thumb_urlstring | The same photo 480 pixels on the long side. |
An example
The newest sign, cut to two of its numbers, its first way and one photo:
{
"id": "01K43VJQP8H8787XQXQDW47W0B",
"slug": "i-35w-at-82nd-street",
"url": "https://roadsignmath.xyz/signs/i-35w-at-82nd-street",
"title": "I-35W at 82nd Street",
"caption": "Tyler found this one driving up I-35W.",
"found_on": "2025-09-01",
"posted_at": "2025-09-02T00:00:13.000Z",
"updated_at": "2025-09-02T00:00:13.000Z",
"posted_by": "jamie",
"place": {
"label": "I-35W at 82nd Street, Bloomington, Minnesota",
"state": "MN",
"lat": 44.857,
"lng": -93.29,
"approximate": true
},
"numbers": [
{
"value": "2",
"text": "HOV 2+",
"why": "Read as 2",
"box": null
},
{
"value": "6",
"text": "6AM-10AM",
"why": "Times split in two",
"box": null
}
],
"finders": [
{
"name": "Tyler",
"handle": "tyler",
"url": "https://roadsignmath.xyz/players/tyler",
"role": "found"
}
],
"way_count": 1,
"ways": [
{
"text": "(90 − 82) ÷ 8 × 1 × 2 = 6 ÷ (10 − 7)",
"tex": "\\frac{90 - 82}{8} \\times 1 \\times 2 = \\frac{6}{10 - 7}",
"value": "2",
"numbers": [
"90",
"82",
"8",
"1",
"2",
"6",
"10",
"7"
],
"by": {
"handle": "tyler",
"name": "Tyler",
"url": "https://roadsignmath.xyz/players/tyler"
},
"created_at": "2025-09-02T00:00:13.000Z"
}
],
"photos": [
{
"id": "01k43vjqp8x8n82dwwwbbwgwhp",
"width": 1600,
"height": 1201,
"alt": "Overhead signs on I-35W: Express Lane (E-ZPass or HOV 2+ only, 6AM-10AM Mon-Fri), Exit 8 82nd St 1 mile, and Exit 7B 90th St.",
"url": "https://roadsignmath.xyz/p/01k43vjqp8x8n82dwwwbbwgwhp/large.jpg",
"thumb_url": "https://roadsignmath.xyz/p/01k43vjqp8x8n82dwwwbbwgwhp/thumb.jpg"
}
]
}Players
https://roadsignmath.xyz/players.json has everyone with a sign or a badge on the map, most signs first: what their page shows, and never an email address.
| Field | What it is |
|---|---|
handlestring | Their handle. Never changes. |
namestring | Their name. |
urlstring | Their page. |
feed_urlstring | Their JSON Feed; feed.xml beside it is Atom. |
biostring or null | What they wrote about themselves. |
avatar_colorstring | The colour behind their first letter when they have no photo. |
avatar_urlstring or null | Their profile photo, 512 pixels square. |
avatar_thumb_urlstring or null | The same, 160 pixels square. |
sign_countnumber | Signs they are a finder on. |
way_countnumber | Ways they found, on anyone’s signs. |
statesarray of strings | The states of their signs, as two-letter codes. |
first_yearnumber or null | The year of their first sign. |
signsarray of strings | The slugs of their signs, newest first. |
badges[].idstring | A badge they earned. There are no points; badges are little road signs for what happened on the road. |
badges[].shelfstring | firsts, places, math, seasons or secret. |
badges[].namestring | Its name. |
badges[].howstring | How it is earned. |
badges[].markstring | What its little sign shows; for a stepped badge, the step reached. |
badges[].earned_onstring | The day it was earned, YYYY-MM-DD. |
badges[].signstring | The slug of the sign that earned it. |
On a map
https://roadsignmath.xyz/signs.geojson is a GeoJSON FeatureCollection with a point for every sign that has a place, ready for Leaflet, MapLibre, QGIS or geojson.io. Most points are the town, not the exact spot. A sign nobody can place is left out; it is still in signs.json, with null coordinates.
| Field | What it is |
|---|---|
idstring | The sign’s id. |
geometry.coordinatesarray | [longitude, latitude], in that order, as GeoJSON has it. |
properties.slugstring | Its name in its address. |
properties.titlestring | Its title. |
properties.urlstring | Its page. |
properties.found_onstring | The day it was found, YYYY-MM-DD. |
properties.placestring | Where it was, in words. |
properties.statestring or null | The two-letter US state. |
properties.approximateboolean | True when the point is the town, not the exact spot. |
properties.mathstring or null | The first way, as plain text. Null when nobody has solved it. |
properties.way_countnumber | How many ways there are. |
properties.findersstring | Who found it, names separated by commas. |
properties.photo_urlstring or null | The first photo, large. |
properties.thumb_urlstring or null | The first photo, small. |
The API
The iPhone app reads and posts through the API at https://roadsignmath.xyz/api/v1, version 1.7.0. These reads are public, JSON with snake_case keys. Its full description is OpenAPI 3.1 at /api/v1/openapi.json. Signing in and posting are for the app. The API is for apps and servers; from a web page, use the files above, which any site can fetch.
GET /api/v1The API version and how many signs, players and states there areGET /api/v1/openapi.jsonThis descriptionGET /api/v1/signsThe latest signs, newest firstGET /api/v1/signs/nearSigns nearest a pointGET /api/v1/signs/similarSigns that may be this oneGET /api/v1/signs/{id}One sign and its waysGET /api/v1/mapEvery sign with a pin, for the mapGET /api/v1/playersWho’s playingGET /api/v1/players/{handle}One player, their signs and their badgesGET /api/v1/badgesEvery badge there is
For agents
- /llms.txt: the game, the pages, the files, the feeds and every sign in a line, for AI tools.
- /llms-full.txt: every sign in full, with the numbers, every way and what each photo shows.
- /sitemap.xml: every page.
- Microformats: Home is an
h-feed, each sign page anh-entry(its name, photo, place, finders and math as LaTeX) and each player page anh-card, so any microformats parser can read them.
Using it
- Everything here is cached for a minute, so there’s no need to fetch it more often. For a feed, once an hour is plenty.
- The format of the files is their
version. Fields may be added; renaming or removing one moves the version on. The API says its version in theAPI-Versionheader. - Only signs on the map are here. A sign that is held back or hidden never is.
- Everything here, the signs, the math, the places, the names and the photos, is shared under CC BY 4.0: use it for anything, as long as you credit the sign’s finders and Road Sign Math, and link to the sign’s page. The site’s code is open source under the MIT licence.