Programme Data
Everything you need to build against the CHI programme is a single JSON file. No API key, no sign-up, no approval step. You can start right now.
https://chidigitalexperience.org/data/chi2027/latest.jsonThat file contains the complete conference programme — sessions, events, contributions ("contents"), people, rooms, and tracks — and it updates as the programme changes, including during the conference itself.
Available now
| Feed | What it is |
|---|---|
/data/chi2026/latest.json | The full CHI 2026 programme. Real data, frozen. Best starting point. |
/data/chi2025/latest.json | The full CHI 2025 programme. Real data, frozen. |
/data/chi2024/latest.json | The full CHI 2024 programme. Real data, frozen. |
/data/chi2023/latest.json | The full CHI 2023 programme. Real data, frozen. |
/data/sandbox/latest.json | A synthetic programme at CHI 2027 scale. Deliberately awkward — see Test against the sandbox. |
Available from April 2027
| Feed | What it is |
|---|---|
/data/chi2027/latest.json | The real CHI 2027 programme, updating through to the end of the conference. |
The 2027 feed is published to everyone at the same URL, with no credentials. There is nothing to apply for and nothing to wait on — the structure is identical to the feeds above.
Checking for updates
Read this bit even if you skip the rest. It is the one thing that is easy to get wrong, and getting it wrong means your app shows attendees a room that changed twenty minutes ago.
Each feed publishes a tiny version.json alongside the programme:
{
"edition": "chi2027",
"revision": 17,
"generated_at": "2027-05-12T09:14:22-04:00",
"latest_url": "https://chidigitalexperience.org/data/chi2027/latest.json",
"revision_url": "https://chidigitalexperience.org/data/chi2027/revisions/017.json"
}Poll version.json with a unique query string, compare the revision to what you already hold, and only fetch the programme when it has moved:
const BASE = 'https://chidigitalexperience.org/data/chi2027';
async function fetchProgrammeIfChanged(knownRevision) {
// The ?t= makes every request a distinct URL, so no cache can answer it.
const res = await fetch(`${BASE}/version.json?t=${Date.now()}`, {
cache: 'no-store'
});
const { revision, revision_url } = await res.json();
if (revision === knownRevision) return null; // nothing new
const programme = await fetch(revision_url).then(r => r.json());
return { revision, programme };
}Poll once a minute during the conference and you will never be more than a minute behind.
Why the ?t=. Our hosting applies ten minutes of browser caching to every file and we cannot change that. A unique URL each time steps around it. The revision files it points you to never change once published, so you can cache those as long as you like — forever, ideally.
About latest.json. It always holds the current programme, and it is perfectly good for exploring the data, for scripts, and for apps that load once at startup. But because of that same ten-minute caching,latest.json can be up to ten minutes out of date in a browser. If your app needs to reflect live changes during the conference, use the pattern above instead. If it doesn't, latest.json is simpler and entirely fine.
Fair use: poll version.json no more than once every 30 seconds (once a minute is plenty), and fetch the immutable revision files rather than re-downloading latest.json in a loop.
What's in the file
The published feed is the conference system's native export (schemeVersion: 7): camelCase field names, epoch-millisecond dates, and top-level collectionssessions / events / contents /people / rooms / tracks / and more. There is currently no status,status_note, or last_modified field, and no soft-delete guarantee. The closest analogue to a content "revision" inside the file itself is publicationInfo.version, not a top-level revision field (that lives inversion.json, described above).
Times are epoch milliseconds. IDs are integers, stable within an edition.
For a full field-by-field breakdown of every collection — conference, sessions, events, contents,people, rooms, tracks, and more — see the Schema Reference. The machine-readable version is published at /data/schema/v1.json, for generating types or validating locally.
Test against the sandbox
/data/sandbox/latest.json is synthetic, sized like a real CHI, and seeded on purpose with things that break conference apps: very long author lists, non-Latin scripts, very long and very short abstracts, overlapping sessions, nulls in optional fields, and more.
There is no live-changing sandbox feed. Test your update-handling logic by hand: fetch sandbox, note the revision, wait for a change to be published, fetch again, and confirm your app picks it up.
What we don't provide
We provide programme data, and nothing about the person using your app. There is no login endpoint, no attendee directory. Personalisation is yours to build — keep it in memory for the session, or inlocalStorage on the attendee's own device.
The simplest way to pass the data protection hurdle is to not collect anything. See Judging.
Full text or PDFs of papers are not provided. Link out via each contribution's DOI / ACM Digital Library link instead.
Licence
The programme data is published under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0).
- Attribution. Credit the source somewhere visible — suggested wording: Programme data © ACM CHI 2027, licensed under CC BY-NC-SA 4.0.
- NonCommercial. Entries must not be commercial.
- ShareAlike. A published derivative of the data must carry the same licence. This does not apply to your app's source code.
The full licence text and this project's specific attribution line are at /data/LICENCE. The licence also travels in each feed's own cc_licence field.
Questions
Anything unclear, anything that looks wrong in the data, anything missing: app@chi2027.acm.org.