The .maxtopia file format
Your data is portable, and the format is public. Here’s the full spec, with schemas and a reference implementation you can use to read or write the files yourself.
Maxtopia stores and shares data in a small, self-describing binary container wrapping gzip-compressed JSON. The format is versioned and backward compatible — files you create today will keep opening in future versions of the app.
The three file types
-
.maxtopia— a shareable workout or program (a template). This is what you send to a friend or client. -
.maxtopiaresults— completed workout results, sent from a client back to a coach. -
.maxtopiabackup— a full export of an app’s data: programs, history, custom exercises, and settings.
All three share the same container; only the fileType byte
and the JSON payload schema differ.
Container structure
A fixed 12-byte header followed by the gzip-compressed JSON payload. All multi-byte integers are big-endian.
Offset Size Field Notes
------ ---- -------------- -----------------------------------------
0 4 magic ASCII "MXTP" (0x4D 0x58 0x54 0x50)
4 2 formatVersion uint16, big-endian (currently 1)
6 1 fileType uint8 (1 = program, 2 = results, 3 = backup)
7 1 flags uint8 (reserved, must be 0)
8 4 payloadCRC32 uint32, big-endian, CRC32 of the payload bytes
12 ... payload gzip-compressed UTF-8 JSON
A reader must verify the magic bytes and the CRC32 of the payload before
trusting a file. Unknown flags bits and unknown JSON fields
must be ignored, never rejected — that’s what keeps the format forward
compatible.
Payload schemas
Program (.maxtopia)
{
"schemaVersion": 1,
"id": "5E9C0B7A-1F2D-4C3E-9A10-7B2C4D6E8F00",
"name": "Beginner Linear Progression",
"author": "Maxtopia",
"createdAt": "2026-05-21T10:00:00Z",
"notes": "Three days a week. Add weight each session.",
"weeks": [
{
"index": 1,
"days": [
{
"name": "Day A",
"exercises": [
{
"exerciseId": "barbell-back-squat",
"name": "Back Squat",
"sets": [
{ "reps": 5, "weight": 60, "unit": "kg", "rpe": 7 },
{ "reps": 5, "weight": 60, "unit": "kg", "rpe": 7 },
{ "reps": 5, "weight": 60, "unit": "kg", "rpe": 8 }
]
}
]
}
]
}
]
} Results (.maxtopiaresults)
{
"schemaVersion": 1,
"programId": "5E9C0B7A-1F2D-4C3E-9A10-7B2C4D6E8F00",
"client": { "displayName": "Sam" },
"sessions": [
{
"date": "2026-05-20T18:32:00Z",
"dayName": "Day A",
"entries": [
{
"exerciseId": "barbell-back-squat",
"sets": [
{ "reps": 5, "weight": 62.5, "unit": "kg", "rpe": 8, "completed": true },
{ "reps": 5, "weight": 62.5, "unit": "kg", "rpe": 9, "completed": true }
]
}
]
}
]
} Backup (.maxtopiabackup)
{
"schemaVersion": 1,
"app": "Maxtopia",
"appVersion": "1.0.0",
"exportedAt": "2026-05-21T10:00:00Z",
"settings": { "units": "kg" },
"programs": [ /* WorkoutProgram[] — same shape as .maxtopia */ ],
"history": [ /* CompletedSession[] — same shape as .maxtopiaresults */ ],
"customExercises": [ /* Exercise[] */ ]
} Versioning policy
-
The container
formatVersionand each payload’sschemaVersionfollow semver. - New optional fields are a minor bump. Readers ignore fields they don’t recognize.
- We commit to backward compatibility forever: any file a released version of Maxtopia ever wrote will keep opening.
- A breaking change (should it ever happen) is a major bump and a new file extension, so old files are never silently misread.
Reference implementation
A complete, dependency-free TypeScript module to read and write the container. Copy it into your own tooling — it’s public domain.
// maxtopia.ts — read and write .maxtopia files. Zero dependencies.
// Works in modern browsers and Node 18+. Released under CC0 (public domain).
// Spec: https://maxtopia.app/file-format
const MAGIC = 0x4d585450; // "MXTP"
export const FORMAT_VERSION = 1;
export enum MaxtopiaFileType {
Program = 1,
Results = 2,
Backup = 3,
}
export interface MaxtopiaContainer<T = unknown> {
formatVersion: number;
type: MaxtopiaFileType;
payload: T;
}
function crc32(bytes: Uint8Array): number {
let crc = 0xffffffff;
for (let i = 0; i < bytes.length; i++) {
crc ^= bytes[i];
for (let j = 0; j < 8; j++) crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1));
}
return (crc ^ 0xffffffff) >>> 0;
}
async function gzip(data: Uint8Array): Promise<Uint8Array> {
const cs = new CompressionStream('gzip');
const out = new Response(new Blob([data]).stream().pipeThrough(cs));
return new Uint8Array(await out.arrayBuffer());
}
async function gunzip(data: Uint8Array): Promise<Uint8Array> {
const ds = new DecompressionStream('gzip');
const out = new Response(new Blob([data]).stream().pipeThrough(ds));
return new Uint8Array(await out.arrayBuffer());
}
export async function encodeMaxtopia<T>(
type: MaxtopiaFileType,
payload: T
): Promise<Uint8Array> {
const json = new TextEncoder().encode(JSON.stringify(payload));
const compressed = await gzip(json);
const header = new DataView(new ArrayBuffer(12));
header.setUint32(0, MAGIC, false);
header.setUint16(4, FORMAT_VERSION, false);
header.setUint8(6, type);
header.setUint8(7, 0); // flags (reserved)
header.setUint32(8, crc32(compressed), false);
const out = new Uint8Array(12 + compressed.length);
out.set(new Uint8Array(header.buffer), 0);
out.set(compressed, 12);
return out;
}
export async function decodeMaxtopia<T = unknown>(
bytes: Uint8Array
): Promise<MaxtopiaContainer<T>> {
if (bytes.length < 12) throw new Error('Not a .maxtopia file: too short');
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
if (view.getUint32(0, false) !== MAGIC)
throw new Error('Not a .maxtopia file: bad magic bytes');
const formatVersion = view.getUint16(4, false);
const type = view.getUint8(6) as MaxtopiaFileType;
const expectedCrc = view.getUint32(8, false);
const compressed = bytes.subarray(12);
if (crc32(compressed) !== expectedCrc)
throw new Error('Checksum mismatch: the file is corrupt');
const json = new TextDecoder().decode(await gunzip(compressed));
return { formatVersion, type, payload: JSON.parse(json) as T };
} License
This specification and the reference implementation above are released into the public domain under Creative Commons Zero (CC0 1.0). Build whatever you want on top of it — importers, exporters, analysis tools — no permission needed.