A single, platform-neutral JSON format for importing completed-event results into
CTFProfile. Conform your scoring data to this shape and it imports cleanly — every
section is optional, and anything missing is flagged to the event's organizers to
fill in later. Current version: ctfprofile-results/v1.
Top-level shape
One JSON object with these arrays. Include only what you have.
{
"format": "ctfprofile-results/v1",
"event": { "name": "Example CTF 2025" },
"challenges": [ ... ],
"teams": [ ... ], // each may contain members[]
"players": [ ... ], // solo competitors
"solves": [ ... ],
"hints": [ ... ], // optional
"opens": [ ... ] // optional
}
Complete example
{
"format": "ctfprofile-results/v1",
"event": {
"name": "Example CTF 2025"
},
"challenges": [
{
"id": "c1",
"name": "Cookie Monster",
"category": "web",
"points": 100,
"description": "Auth bypass via an unsigned session cookie.",
"author": "webwyrm"
},
{
"id": "c2",
"name": "Heap Lantern",
"category": "pwn",
"points": 450,
"description": "Tcache poisoning into code execution.",
"author": "cipherlynx"
}
],
"teams": [
{
"id": "t1",
"name": "Null Pointers",
"score": 550,
"rank": 1,
"members": [
{
"id": "u1",
"name": "cipherlynx"
},
{
"id": "u2",
"name": "webwyrm"
}
]
}
],
"players": [
{
"id": "u9",
"name": "soloist",
"score": 100,
"rank": 2
}
],
"solves": [
{
"id": "s1",
"challenge_id": "c1",
"team_id": "t1",
"user_id": "u2",
"timestamp": "2025-01-01T10:15:00Z"
},
{
"id": "s2",
"challenge_id": "c2",
"team_id": "t1",
"user_id": "u1",
"timestamp": "2025-01-01T12:40:00Z"
},
{
"id": "s3",
"challenge_id": "c1",
"user_id": "u9",
"timestamp": "2025-01-01T11:05:00Z"
}
],
"hints": [
{
"challenge_id": "c2",
"user_id": "u1",
"timestamp": "2025-01-01T12:10:00Z"
}
],
"opens": [
{
"challenge_id": "c1",
"user_id": "u2",
"timestamp": "2025-01-01T10:00:00Z"
}
]
}