Post-Event Report
After a CTF event concludes, CTFFactory compiles a structured post-event report that captures participant performance, challenge solve rates, scoring distribution, and operational metrics. This report is the primary tool for retrospective analysis and for demonstrating the value of the event to stakeholders.
Accessing the Report
The post-event report becomes available within a few minutes of the event end time.
- In the UI: navigate to the event and click Report in the top navigation.
- Via API: retrieve the full report as a structured JSON document through the REST API.
GET /api/v1/events/{event_id}/report
Authorization: Bearer {api_key}
The response is a single JSON object containing all report sections described below.
[!NOTE] The report endpoint is available for all events, including those that ended early or were cancelled. Incomplete events produce a partial report reflecting the data collected up to termination.
Report Structure
The full JSON report contains the following top-level keys:
{
"event": { ... },
"summary": { ... },
"participants": [ ... ],
"challenges": [ ... ],
"timeline": [ ... ],
"difficulty_retrospective": { ... }
}
event β Event Metadata
Basic event information: name, ID, start and end timestamps, scoring mode, total registered participants, and deployment region.
summary β Aggregate Statistics
High-level numbers for quick reporting:
| Field | Description |
|---|---|
total_participants |
Number of registered participants (or teams in team mode) |
active_participants |
Participants who made at least one solve attempt |
total_solves |
Sum of all correct flag submissions across all challenges |
overall_solve_rate |
total_solves / (active_participants Γ challenge_count) |
median_score |
Median participant score at event end |
top_score |
Highest individual or team score |
duration_seconds |
Actual event duration |
participants β Per-Participant Statistics
An array of objects, one per participant or team, sorted by final rank:
{
"rank": 1,
"name": "team_name",
"score": 2450,
"solves": 12,
"first_blood_count": 3,
"last_solve_at": "2025-06-15T18:42:00Z",
"solve_history": [
{ "challenge_id": "web-001", "solved_at": "...", "points_awarded": 200 }
]
}
challenges β Per-Challenge Statistics
An array of objects, one per challenge, that captures how each challenge performed:
| Field | Description |
|---|---|
challenge_id |
Internal challenge identifier |
title |
Challenge title |
category |
Technical category |
difficulty |
Configured difficulty level |
points |
Final point value (at event end for dynamic scoring) |
solve_count |
Number of participants who solved it |
solve_rate |
solve_count / active_participants |
first_blood |
Participant name and timestamp of first solve |
median_solve_time_seconds |
Median time from event start to solve across all solvers |
incorrect_attempts |
Total incorrect flag submissions |
attempt_to_solve_ratio |
incorrect_attempts / solve_count β a proxy for challenge friction |
timeline β Event Timeline
A chronological log of significant events: first participant joined, first solve, scoreboard freeze (if applied), challenge releases (if challenges were released progressively), and event end.
difficulty_retrospective β Calibration Analysis
[!TIP] The difficulty retrospective is the most actionable section for organizers improving future events.
This section compares the configured difficulty of each challenge against its observed difficulty (derived from solve rate and median solve time). Mismatches indicate calibration drift between the AI-generated difficulty label and actual player behavior.
{
"web-001": {
"configured_difficulty": "medium",
"observed_difficulty": "easy",
"solve_rate": 0.87,
"median_solve_time_seconds": 420,
"calibration_verdict": "easier_than_labeled"
}
}
Possible calibration verdicts:
| Verdict | Meaning |
|---|---|
well_calibrated |
Solve rate and time match the expected range for the difficulty label |
easier_than_labeled |
Challenge was solved by significantly more participants or faster than expected |
harder_than_labeled |
Challenge was solved by significantly fewer participants or slower than expected |
unsolved |
No participant solved the challenge during the event |
Use the difficulty retrospective to adjust point values for re-used challenges, refine your generation prompts, or select different challenge specs in future events.
Exporting the Report
From the UI, the report can be exported as:
- JSON β the full machine-readable document
- CSV β participant rankings and per-challenge solve counts in tabular form
- PDF β a formatted summary suitable for sharing with stakeholders
The JSON export is identical to the API response and can be ingested by external BI tools, LMS platforms, or custom dashboards.
[!WARNING] Post-event reports contain participant names, email addresses (for workspace members), and solve timestamps. Handle exported reports in accordance with your organization's data retention and privacy policies.
Webhook Delivery
If your workspace has a webhook configured for the event.report.ready event type, CTFFactory delivers the full JSON report to your endpoint automatically when the report is compiled. This eliminates the need to poll the API.
{
"event_type": "event.report.ready",
"event_id": "evt_abc123",
"report_url": "https://api.ctffactory.io/v1/events/evt_abc123/report",
"generated_at": "2025-06-15T19:05:00Z"
}
See the Webhooks documentation for payload signing and retry behavior.