The take-exam flow is not yet available in the production environment. It is currently available on staging only.
Using the Examplary take exam flow, you can embed the full student-facing exam experience for an existing exam directly into your application. From within the embed, your students can take the exam and submit their answers.
This flow is intended for a single exam session: the student takes the exam once, answers all questions, and submits. Each answer is persisted in real time.
Presets
| Key | Type | Description |
|---|---|---|
examId | string | The ID of the exam that should be taken by the student. Must start with exam_. Required. The actor user must have access to take this exam. |
Example
1. Create an Examplary user for your student
Each student needs an Examplary user account in your workspace. This is how we attribute answers and sessions to the individual student.
{
"email": "my-student@example.com",
"name": "My Student"
}Store the returned user ID in your system — you'll use it as the actor for the student's embed sessions.
2. Make sure an exam exists and the actor can take it
The take exam flow operates on an existing exam. If you don't have one yet, create it first (API reference).
The student user must be given the participant role on the exam — this is what allows them to take it and submit answers:
{
"name": "Midterm Exam - Algebra",
"subject": "Mathematics",
"questions": [
// ...
],
"permissions": [
{
"actor": "ACTOR_USER_ID",
"role": "participant"
}
],
"metadata": {
"my_service_internal_id": "abc1234"
}
}3. Create an embed session
Call the Examplary API to create a new embed session for the take-exam flow. The only required preset is examId — the ID of the exam to take.
The actor field should contain the ID of the Examplary user account you created for the student.
Specify an allowedOrigin if you want to listen for postMessage updates from the iframe.
{
"flow": "take-exam",
"actor": "user_423r9j3r0jeddJA...",
"presets": {
"examId": "exam_55S843D7HfNfs9RY48..."
},
"theme": {
"primaryColor": "#4f46e5",
"locale": "en"
},
"metadata": {
"my_service_internal_id": "abc1234"
},
"allowedOrigin": "https://app.example.com"
}This returns a response that looks like this:
{
"id": "embed_session_55S843D7HfNfs9RY48PoTprXnRcz2Vw8Crst64UYrBnz...",
"status": "pending",
"embedUrl": "https://app.examplary.ai/embeds/55S843D7HfNf...",
"flow": "take-exam",
"actor": "user_423r9j3r0jeddJA...",
"enabledResponseModes": ["post_message"],
"createdAt": "2025-12-09T16:52:52.120Z",
"expiresAt": "2025-12-16T16:52:52.120Z",
"presets": {
"examId": "exam_55S843D7HfNfs9RY48..."
},
"outputs": {},
"theme": {
"primaryColor": "#4f46e5",
"locale": "en"
},
"metadata": {
"my_service_internal_id": "abc1234"
}
}4. Lead the student to the embed URL
You can either redirect the student directly to the URL, or display it in an iframe. Embedding inside an iframe is usually preferable so the student stays inside your application.
If you specified an allowedOrigin, you can listen for status updates via the postMessage API:
const embedUrl = "https://app.examplary.ai/embeds/55S843D7HfNf...";
iframe.src = embedUrl;
window.addEventListener("message", (event) => {
// Make sure the message is coming from a trusted origin
if (event.origin !== new URL(embedUrl).origin) return;
const { type, status } = event.data;
if (type === "examplary:embed-status-update") {
if (status === "started") {
// Fired each time the student answers a question
console.log("Question answered");
} else if (status === "completed") {
// The student handed in the exam or the session reached the time limit
console.log("Exam completed");
}
}
});The following status values are emitted during a take-exam session:
| Status | Description |
|---|---|
started | Fired each time the student answers a question |
completed | The student handed in the exam, or the session reached the time limit |
5. Cleanup
The embed session will expire automatically after 7 days, but because it gives some limited access to your account, you might want to remove it manually:
DELETE /embed-sessions/{embedSessionId}