Debug Mode and validation feedback
Debug Mode gives you detailed feedback on how your events match the published schema. Use it while implementing tracking to inspect field types, required values and unknown fields directly in the response.
Add the debug headers below, send an event and read its validation results. With Server-GTM, you can also return this feedback through JSON Client to the browser and display it in the console.
Enable Debug Mode
| Sender to Platform | Additional debug headers |
|---|---|
| Backend or Server-GTM with a server key | X-DDA-Debug: true |
| Direct browser request with a browser key | X-DDA-Debug: true and X-DDA-Debug-Token: <token-for-this-browser-key> |
Keep the normal Authorization, Content-Type and schema-version headers. The debug
token is separate from the browser ingestion key. The flag must have the literal
value true. It requests details for that request, rather than enabling a persistent
mode for the entire environment.
Server request headers:
Authorization: Bearer <server-key>
Content-Type: application/json
X-DDA-Event-Schema-Version: <published-version>
X-DDA-Debug: true
Direct browser request headers:
Authorization: Bearer <browser-key>
Content-Type: application/json
X-DDA-Event-Schema-Version: <published-version>
X-DDA-Debug: true
X-DDA-Debug-Token: <debug-token-for-this-browser-key>
Add X-DDA-Debug: true to your request. With a server key, that header is sufficient.
With a browser key, also send X-DDA-Debug-Token using the debug token for that exact
key from Ingestion keys. A token for another key in the same environment does
not work.
Use the browser token only in a controlled debugging session. Do not embed it in code distributed to every visitor. A cookie or tag-manager preview flag alone does not enable API diagnostics. Your integration must send the headers.
View validation feedback
Send an event with the debug headers and open the response in the browser's Network
panel, your tag manager's preview or your HTTP client's response viewer.
results[].validation.status shows the validation outcome for each event.
With debug enabled, results[].validation.issues adds details about warnings and
errors, for example:
{
"severity": "warning",
"code": "schema_unknown_field",
"path": "events[0].campaign.internal",
"message": "The field is not part of this event schema version and was discarded.",
"observedType": "string",
"action": "removed"
}
The path identifies the affected field. Compare it with the published version used by the sender, not only the current draft. Diagnostics may be truncated. Debug does not change acceptance rules or activate validation mode. A missing or invalid browser debug token leaves the compact response in place without stopping event ingestion.
Interpret the event result
results[].status | Meaning | Next step |
|---|---|---|
sampled_for_schema_discovery | Used to discover structure | Review and publish the schema, then update the sender |
validated_only | Checked without collection | Configure and test the destination, then send fresh events |
queued | Accepted for processing | Verify destination status and warehouse delivery |
duplicate | Identical event already accepted within the deduplication window | Check the original event and your trigger or retry behavior |
filtered | Excluded by bot or consent rules | Inspect reason and the relevant mapped event fields |
rejected | This event was not accepted | Inspect code and validation details, then correct it |
validation.status is separate from the processing status. It can be passed,
warning, failed or not_run. A warning can mean an unknown field was removed.
A passed schema check does not guarantee warehouse delivery. Check every result in
a batch rather than treating HTTP 202 as success for every event.
Return validation feedback through Server-GTM
This integration uses three components with different roles:
| Component | Runs in | Role |
|---|---|---|
| JSON Tag | Browser, typically through Web-GTM | Sends the event to your tagging server and receives its response |
| JSON Client | Server-GTM, as a client template | Receives the incoming request, prepares Event Data and makes it available to server tags |
| JSON Server Tag | Server-GTM, as a tag template | Sends the event to Platform and passes its response back to JSON Client |
This lets you bring Platform validation feedback back to the browser during development:
Browser: JSON Tag → Server-GTM: JSON Client → JSON Server Tag → Platform
Browser: JSON Tag ← Server-GTM: JSON Client ← JSON Server Tag ← validation response
- Configure JSON Tag in the browser, typically through Web-GTM, to send events to your tagging server. In Server-GTM, configure JSON Client to receive requests at that path and prepare their Event Data. Configure JSON Server Tag to run on those events and forward them to Platform with its server key and schema version.
- In the tag's Custom Request Headers, add
X-DDA-Debugwith valuetruefor your controlled development or preview requests. No Platform browser debug token is needed on this server-to-server hop. - Under Response Settings, enable Send Response to JSON Client. Set
Response Key to a recognizable value, such as
platform_validation. - Trigger a test event through JSON Tag. Inspect the response from your tagging server.
Its tag response contains Platform's
requestIdandresults. - Read
results[].validation.issuesto see field-level feedback while developing. Also checkresults[].status, even if Server-GTM marks the HTTP call successful.
JSON Server Tag already implements the response forwarding option. You do not need to modify its template code. See its Response Settings documentation.
The current JSON Client returns an array under responses, including for a single
event. Each entry contains its tag data under tags. JSON Tag can also expose this data in its
Data Layer push. See JSON Client response forwarding
and batch responses.
Print validation results with a Web-GTM Custom HTML tag
This example groups results in the browser console, highlights queued events and shows validation issues as a table. It runs in the web container, after JSON Tag has received the response from your tagging server.
- Enable Send Response to JSON Client in JSON Server Tag. For this script, set
Response Key to
dda. If you usedplatform_validationabove, either change that setting or replaceresponse.tags.ddain the script withresponse.tags.platform_validation. - In Web-GTM Preview, find the Data Layer event where JSON Tag supplies the returned
response. Create a Data Layer Variable pointing to the complete parsed JSON Client
response object, including
responses. Name the GTM variableJsonclient Response (Data Layer Variable)to match the reference below. The variable name is not the Data Layer path. Select that path from your actual push. - Create a Custom HTML tag in the web container and paste the script below.
- Enable Push Response in Data Layer in JSON Tag Settings. Create a Custom
Event trigger with event name
jsonclientResponse(case-sensitive). You can name the trigger JSON Client Response. If you changed Data Layer Event Name in JSON Tag Settings, use that configured value instead. Trigger on the response, not the earlier outgoing tracking event. - Send an event, open the browser console and expand its result group.
Only show console output in debug sessions
Enable the built-in Debug Mode variable under Variables → Configure in the web container. It indicates GTM preview/debug mode. Add an exception to the console tag:
| Setting | Value |
|---|---|
| Firing trigger | Custom Event jsonclientResponse |
| Exception trigger | Custom Event jsonclientResponse, Some Custom Events |
| Exception condition | {{Debug Mode}} does not equal true |
Attach the exception under the tag's Exceptions. Both triggers evaluate the same response event. Outside preview/debug mode, the exception blocks the console tag.
Alternatively, create a 1st Party Cookie variable for your own debug cookie,
for example tracking_debug. Use a custom-event exception for the same response
event with the condition that this variable does not equal 1. Set the cookie to
1 for your debug session. An absent cookie also leaves console output blocked.
If either GTM preview or the cookie should enable output, put both negative conditions
in one exception: Debug Mode does not equal true and cookie does not equal 1.
These conditions control the console tag only. They do not enable Platform's
X-DDA-Debug header or the server-side response forwarding. Configure those separately.
Check in Preview that the tag fires when your chosen debug condition is enabled
and is blocked when it is disabled.
References: JSON Tag Settings response configuration, GTM built-in variables and trigger exceptions.
The {{...}} reference is a GTM variable, not standalone JavaScript. Adjust it if
your variable has another name. The script only reads and displays the response.
It does not send events or enable the debug headers for you.
<script>
(function () {
var client = {{Jsonclient Response (Data Layer Variable)}};
var con = window.console;
if (!con || !client || !Array.isArray(client.responses)) return;
var successStyle =
"background: #dcfce7; color: #166534; padding: 3px 8px; " +
"border-radius: 4px; font-weight: bold;";
var warningStyle =
"background: #ffedd5; color: #9a3412; padding: 3px 8px; " +
"border-radius: 4px; font-weight: bold;";
client.responses.forEach(function (response, responseIndex) {
var feedback = response && response.tags && response.tags.dda;
if (!feedback) return;
var requestId = feedback.requestId || "unknown";
if (!Array.isArray(feedback.results)) {
con.log("%c[Drag & Drop Analytics] NO EVENT RESULTS", warningStyle, {
requestId: requestId,
status: feedback.status,
code: feedback.code,
message: feedback.message
});
return;
}
feedback.results.forEach(function (result) {
if (!result) return;
var validation = result.validation || {};
var issues = Array.isArray(validation.issues) ? validation.issues : [];
var passed = validation.status === "passed" &&
issues.length === 0 && !validation.truncated;
var success = passed && result.status === "queued";
var headline;
if (success) {
headline = "✓ QUEUED";
} else if (result.status === "rejected" || validation.status === "failed") {
headline = "⚠ FAILED";
} else if (issues.length || validation.status === "warning" || validation.truncated) {
headline = "⚠ VALIDATION ISSUES";
} else {
headline = (result.status || "UNKNOWN").toUpperCase();
}
var label = "[Drag & Drop Analytics] " + headline +
" | Response " + responseIndex +
" | Event index " + result.index +
" | " + result.status +
" | Validation: " + (validation.status || "unknown");
con.groupCollapsed("%c" + label, success ? successStyle : warningStyle);
con.log("Request ID:", requestId);
if (issues.length) {
var rows = issues.map(function (issue) {
return {
Severity: issue.severity || "",
Code: issue.code || "",
Path: issue.path || "",
Message: issue.message || "",
ExpectedType: issue.expectedType || "",
ObservedType: issue.observedType || "",
Action: issue.action || ""
};
});
if (con.table) con.table(rows);
else con.log(rows);
}
if (validation.truncated) {
con.warn("Diagnostics were truncated. Additional issues are not shown.");
}
if (passed) {
con.log(result.status === "queued"
? "✓ Valid, with no validation issues. Added to the queue."
: "✓ Validation passed with no validation issues.");
} else if (!issues.length && !validation.truncated) {
if (validation.status === "not_run") {
con.info("Validation was not performed, e.g. during schema discovery.");
} else {
con.warn("Validation status:", validation.status || "unknown",
"| No issue details included in the response.");
}
}
if (result.status === "rejected") {
con.error("Event rejected:", result.code || "no error code provided");
} else if (result.status === "filtered") {
con.info("Event filtered:", result.reason || "no reason provided");
} else if (result.status === "duplicate") {
con.info("Duplicate detected. Not added to the queue again.");
}
con.groupEnd();
});
});
})();
</script>
Green QUEUED means validation passed and the event was added to the queue.
It does not confirm warehouse delivery. Other groups show validation warnings,
rejections, filtering, duplicates or validation-only results. Truncated diagnostics
are explicitly marked. Empty detail columns mean that the response did not include
that property. The current Platform diagnostics do not provide expectedType, so
that optional column remains empty.
For detailed field feedback, enable the server-side debug header as described above. The script cannot recover details that were not included in the response.
Check the feedback loop during development
In a test environment, send a valid event, then one with a deliberately wrong type
for a required field. Confirm that the latter returns rejected, validation
failed and an issue identifying the field. Fix it and send a fresh event.
An extra undeclared field can produce a warning and be removed without rejecting
the whole event. This makes it possible to distinguish warnings from failures before
publishing tracking changes.
Restrict detailed response forwarding to your intended debugging audience. A debug header added unconditionally by the server tag can expose diagnostics to every caller receiving its response. Remove or condition that header and response forwarding when leaving the development workflow. Keep the server key on the server.
Diagnose HTTP errors
| HTTP status | What to check |
|---|---|
400 | JSON shape, required fields, field types and schema-version header. Read the error code or per-event results |
401 | Missing, invalid, expired or revoked ingestion key |
403 | Browser origin allowlist, key type and actual request origin |
409 | Producer event ID reused with conflicting content |
413 | Event size, total request size or batch count |
429 | Rate limit or quota. Follow response information and Retry-After when present |
503 | Temporary ingestion or processing unavailability. Preserve stable event IDs for bounded retries |
Do not retry every 4xx response unchanged. Fix its cause. A batch may contain both
accepted and rejected events, so the HTTP status alone is not the full diagnosis.
When the warehouse or report is empty
- Confirm the event went to the intended environment and destination.
- Inspect its result. Discovery and validation-only events will not be delivered later.
- For
filtered, check consent mappings, destination requirements and the mapped User-Agent used for bot detection. - For
queued, check the destination connection and Collection needs attention hints. Acceptance is not a warehouse acknowledgement. - If the event is in the warehouse, check the Explorer data source, read permissions, date range, timezone, selected metric and filters.
After a change, send a new event to see the updated validation feedback.