Measurement lab · Digital marketing
A clean validation result leaves the secret untested
Use the debug response to inspect the payload, then verify the destination separately.
- Dummy credentials can passThree well-named test requests returned no validation messages despite using made-up stream IDs and secrets.
- A negative control checks the checkerThe same endpoint reported NAME_INVALID when we deliberately prefixed the event name with an underscore.
- Validation does not record an eventCheck the real stream configuration and controlled collection evidence before declaring delivery successful.
An empty validationMessages array from GA4's Measurement Protocol validation server does not prove that your API secret works. In a four-request test, we received a clean response with two deliberately fake secrets and two made-up stream IDs. The same endpoint correctly caught an invalid event name. It was doing its job; that job did not include authenticating our destination.
That distinction matters when a backend says an event was “sent successfully” but nobody can find it in Analytics. Before changing a payload that already passes validation, establish which endpoint produced that reassuring response and what it actually checked.
A fake secret passed our controlled check
On 25 September 2026, we sent four HTTPS POST requests to /debug/mp/collect, Google's validation-only endpoint. Every request used the same synthetic client ID and ENFORCE_RECOMMENDATIONS. We changed one input at a time from a baseline with a valid event name: first the name, then the secret, then the stream ID.
The invalid name _pmd_probe produced NAME_INVALID. Removing its leading underscore produced no validation messages. Replacing the dummy secret did not change that result. Neither did replacing the dummy stream ID. All four HTTP responses were 200, including the response that contained the naming error.
Four live debug requests · 25 September 2026
The name changed the result. The dummy credentials did not.
Invalid name
_pmd_probe · secret A · stream 001 HTTP 200 · NAME_INVALID
Corrected name
pmd_probe · secret A · stream 001 HTTP 200 · no messages
Different secret
pmd_probe · secret B · stream 001 HTTP 200 · no messages
Different stream
pmd_probe · secret A · stream 002 HTTP 200 · no messages
All credentials were synthetic. No request was sent to /mp/collect. Stream 001 and 002 abbreviate G-PMDTEST001 and G-PMDTEST002.
The negative control is the important part of this comparison. Without it, three empty responses could leave us wondering whether the test reached a functioning validator at all. Seeing the naming error disappear after the one-character correction shows that the endpoint distinguished these payloads while remaining silent about our dummy credentials.
This experiment used no real Analytics secret and sent nothing to the collection endpoint. It makes no claim about a property's reports, conversion attribution or processing time. Its conclusion is narrower: a clean validation response can coexist with credentials that we deliberately did not obtain from a real stream.
The debug endpoint leaves the destination untested
Google's web-stream validation guide explicitly excludes api_secret and measurement_id from this validation. It also says debug requests do not populate reports. Our observed responses are consistent with those two boundaries.

There is a second boundary at the collection endpoint. According to Google's Measurement Protocol transport reference, a 2xx response acknowledges receipt of the HTTP request even when the payload is malformed, incorrect or unprocessed. We did not test collection in this experiment. In particular, the four 200 responses above must not be presented as four accepted Analytics events.
For an implementation owner, this suggests three separate entries in a test record: the request reached an endpoint; the validator reported no issues; the intended property showed the expected event. Each entry needs its own evidence. A log line that collapses them into “success” removes exactly the distinction needed to investigate a missing event.
Give the validator a failure it should catch
Here is a small Node.js reproduction using only dummy values. Save it as validate-probe.mjs and run node validate-probe.mjs on Node 18 or later. It contacts Google's debug endpoint four times. It does not send collection events or need your real API secret.
// Validation only. These values are deliberately fake.
const cases = [
['_pmd_probe', 'not-a-real-secret-a', 'G-PMDTEST001'],
['pmd_probe', 'not-a-real-secret-a', 'G-PMDTEST001'],
['pmd_probe', 'not-a-real-secret-b', 'G-PMDTEST001'],
['pmd_probe', 'not-a-real-secret-a', 'G-PMDTEST002']
];
for (const [name, secret, stream] of cases) {
const url = new URL(
'https://www.google-analytics.com/debug/mp/collect'
);
url.searchParams.set('measurement_id', stream);
url.searchParams.set('api_secret', secret);
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
signal: AbortSignal.timeout(15000),
body: JSON.stringify({
client_id: '123456789.987654321',
validation_behavior: 'ENFORCE_RECOMMENDATIONS',
events: [{ name, params: {} }]
})
});
if (!response.ok) throw new Error('HTTP ' + response.status);
const result = await response.json();
console.log(name, stream, result.validationMessages);
}
The expected response pattern is one NAME_INVALID result followed by three empty arrays. This is an observation from our test date, not a promise that every invalid field will yield one message or that validator behavior can never change. If the negative control returns no useful error, inspect the destination, response body and current documentation before trusting the rest of the test.
For a real payload, repeat the structure check with the event you actually intend to send. A custom probe proves only that the probe passed. It cannot establish that a purchase has the correct item quantities, that an identifier survived serialization or that the recorded business action happened. The order-ID precision failure is one example of a payload becoming wrong before a tag can inspect it.
Verify the stream outside the validation response
Start with the Web data stream in GA4 Admin. Match its Measurement ID to the deployed server configuration and confirm that the secret belongs to that same stream, remains valid and has been copied exactly. Google's troubleshooting guide calls out wrong-stream secrets, revocation and case-sensitive copying. Changing only the event body cannot repair those mismatches.
Keep the real secret in a trusted backend. The sending guide distinguishes the Web pair measurement_id and client_id from Firebase's app identifiers, and cautions against exposing secrets in browser code. Do not replace the dummy values in this example and paste the result into a public page.
- Configuration evidence — the deployed Web Measurement ID and secret belong to the intended stream; record the check without logging the secret.
- Payload evidence — retain the redacted payload and validator response, including the deliberately invalid control.
- Delivery evidence — observe the expected controlled event in the intended property and confirm the parameters relevant to the test.
Use an appropriate test property and an event you can identify. Validate that exact payload first, then perform a controlled collection test with the real stream configuration. Google recommends strict validation during development and omitting validation_behavior from production requests to reduce rejected data. Keep a record of which payload and validation setting each result belongs to.
Choose the observation surface deliberately. The Measurement Protocol reference recommends session_id and engagement_time_msec for accurate session and engagement metrics, including Realtime. Supply values that reflect the actual interaction when those metrics are part of the test; fabricated engagement is not a fix for missing evidence. A debug-validation result alone supplies none of that reporting evidence.
Keep one missing event separate from other measurement problems
An observed test event establishes more than a clean validator response, but it still does not prove every production event is correct. A purchase amount may be wrong, a client identifier may link the event to the wrong context, or a second sender may duplicate the action. The SPA page-view diagnosis covers that separate duplicate-sender problem.
The same discipline helps with Pinterest clicks that never become website sessions: inspect the boundary where the evidence stops. For this GA4 problem, the useful next action after a clean debug response is to check the intended destination and controlled delivery. Repeatedly obtaining the same empty array cannot answer a question the validator does not ask.
Questions about GA4 validation and missing events
Does an empty validationMessages array mean the API secret is valid?
No. The debug validator does not authenticate the stream ID or secret. Our well-named requests returned empty arrays with dummy values.
Why did the invalid request also return HTTP 200?
The HTTP status described the successful exchange with the validator. Its JSON response carried NAME_INVALID. Inspect the body instead of using status alone as the validation result.
Will the debug requests appear in GA4 reports?
No. The debug endpoint validates requests without adding their events to reports. A collection test is separate.
Does a 204 collection response prove delivery?
Google documents 2xx collection responses as HTTP receipt, without guaranteeing that the data was processed. Our experiment used the debug endpoint only; it did not test a live collection or report.
Google documentation and experiment provenance
- Validate events — Web-stream validator scope and strict development checks.
- Measurement Protocol reference — HTTP transport semantics and reporting parameters.
- Send Measurement Protocol events — stream identifiers and trusted handling of real secrets.
- Troubleshooting — stream, secret and identifier checks.
Documentation checked 25 September 2026. Original experiment: four validation-only HTTPS requests from PowerShell, synthetic client and stream identifiers, two dummy secrets, strict validation enabled. The separately executed Node.js reproduction returned the same result pattern. Raw responses and scripts retained in editorial sources. No collection requests or report inspection.




