Track successful form submissions, not just button clicks
In Clicktag, track form conversions only after your server confirms success rather than logging button clicks. This prevents validation errors from inflating goals, while keeping custom metadata payloads within 4,096 characters.
The Problem with Click Intent Tracking
Attaching an analytics tracker directly to a submit button click or an unvalidated DOM submit event records intent rather than success. When a user clicks submit on a form with an invalid email address, empty required fields, or a duplicate record, the click fires regardless. If your analytics script logs that interaction immediately, every validation error registers as an achieved goal.
Measuring intent helps diagnose interface friction, but relying on clicks for primary conversions introduces substantial error. For example, if 1,000 visitors click a submit button, but 300 abandon the flow due to inline validation errors or payment rejects, leaving 700 actual signups, counting clicks overstates conversions by about 43 percent (this example is hypothetical and illustrative). Accurate analytics require separating the attempt from the verified outcome.
| Event Name | Trigger Point | Reliability | Primary Purpose |
|---|---|---|---|
submit_button_clicked |
DOM click event on submit button |
Low (captures failures) | Form friction diagnostics |
form_attempted |
DOM submit event after browser validation |
Attempt only (server may reject it) | Submission attempt count |
signup_completed |
Confirmed server response with valid status | High (verified submission) | Funnel step, core conversion metric |
checkout_completed |
Server confirmation or receipt payload | High (verified submission) | Revenue tracking, business goals |
Client-Side Buffer Queue and Safe Event Invocation
Clicktag provides the window.tt_event function through its tracking script. If a user completes a fast form before latest.js finishes loading in the background, calling window.tt_event directly throws a ReferenceError unless buffered.
To capture early events reliably, place an asynchronous buffer queue snippet in your document head before loading the script:
<script>
window.tt_event =
window.tt_event ||
function () {
window.tt_event.q.push(Array.from(arguments));
};
window.tt_event.q = window.tt_event.q || [];
</script>
<script
async
src="https://clicktag.io/latest.js"
data-hostname="example.com"
data-verify="your_verification_token"
></script>
Always use standard function () syntax rather than an arrow function so the runtime preserves the arguments object required by Array.from(arguments). When latest.js completes execution, it inspects window.tt_event.q and replays all buffered calls in sequence. If the q array is omitted, the script cannot drain queued calls.
Dispatching Events After Server Confirmation
To record authentic completions, trigger your event dispatch inside a response handler that explicitly confirms backend success. Rather than coupling analytics to DOM buttons, isolate tracking in a generic handler function:
function recordSuccessfulSignup(result) {
if (!result || !result.success) {
console.error('Signup was not successful');
return;
}
if (typeof window.tt_event === 'function') {
window.tt_event('signup_completed', {
plan: typeof result.plan === 'string' ? result.plan : 'unknown'
});
} else {
console.warn('Clicktag tt_event is not available');
}
}
This function verifies the payload before dispatching the custom event. If the backend reports an error status or returns invalid data, the function logs the problem and skips the analytics call entirely.
Review the custom events documentation for naming specifications. Event names are normalized automatically by Clicktag using a strict sequence: names are truncated to 256 characters first, any character sequences that are not ASCII letters or digits are replaced with underscores, and leading or trailing underscores are stripped.
Metadata Rules and API Limitations
Event metadata passed to window.tt_event must be a plain JavaScript object composed of compact strings, numbers, or booleans. Clicktag enforces strict payload constraints:
- Payload size limit: The collector accepts a maximum of 4,096 characters of serialized metadata JSON. Payloads exceeding this limit are truncated, which can produce invalid JSON.
- No personal data: Never include personal data in event metadata. Do not log email addresses, phone numbers, individual user identifiers, names, or postal addresses.
- No stats API retrieval or filtering: Custom metadata is not exposed for retrieval, grouping, or filtering by the stats API. Furthermore, custom metadata keys cannot be used to filter steps in dashboard funnels.
- Live view inspection: The real-time live view displays only the first 512 characters of the metadata payload for diagnostic checks.
Because metadata cannot be queried or aggregated via the stats API, differentiate core business variants directly within the event name (such as signup_starter versus signup_enterprise) or isolate them by page path.
Understanding the Analytics Callback
window.tt_event accepts an optional third argument callback that executes after the tracking image request completes or fails:
window.tt_event('signup_completed', { plan: 'pro' }, function () {
console.log('Event dispatch finished');
});
Never treat this callback as proof of database persistence or business completion, and never block application navigation waiting for it. The callback runs under specific client-side conditions:
- When the tracking network call succeeds or fails.
- Immediately, without sending any network request, if the event name is not a valid string, number, or function.
- The callback will never fire if the event name collapses to an empty string after character cleaning (for instance,
"!!!").
Because the callback cannot confirm persistence on the server collector and may fire without sending data, drive your user interface feedback strictly from your backend API responses.
Session Continuity and Multi-Step Funnels
Clicktag supports server-side event dispatch via POST /events. While backend tracking works well for offline processing like invoice settlements, server dispatch changes how visitor identities are calculated.
In client-side tracking, visitor hashes are computed using the visitor IP, user-agent, site hostname, the UTC day, and a rotating daily salt. When an event is dispatched from a backend server via POST /events, the collector hashes your server IP address instead of the end-user browser IP. Clicktag does not accept visitor IP overrides. As a result, backend events cannot connect to an active browser session or inherit the visitor initial landing page and referrer.
To build working multi-step conversion flows in goals and funnels, trigger the conversion event in the browser using window.tt_event once your server responds with success. This ensures the visitor hash matches between the initial pageview and the terminal conversion step for that UTC day, allowing clean evaluation on your dashboard.
Frequently Asked Questions
Why does my conversion funnel show zero completions when backend events fire successfully?
Clicktag funnels match visitor hashes across steps during the same UTC day. Server-side events sent through POST /events calculate visitor identity using your application server IP rather than the user browser IP. Because Clicktag does not accept client IP overrides, server-sent events cannot join a funnel that started with a browser pageview. Fire window.tt_event from the browser after your backend returns success to maintain session continuity.
Can I segment goal conversion rates using custom metadata properties?
No. Clicktag goals and funnels can be filtered by page path, referrer, country, device, browser, operating system, and standard UTM parameters (source, medium, campaign). Filtering or grouping by custom event metadata keys is not supported in the stats API or reporting views. If you need distinct metrics for specific plans or tiers, record dedicated event names instead.
What happens if a user navigates away before the tracking request finishes?
Modern browsers process asynchronous image requests in the background once initiated. However, if a user closes the window immediately, the tracking request may be aborted before reaching the collector. Do not attempt to force artificial delays or await the window.tt_event callback, as the callback cannot confirm persistence and adding latency harms the user experience.
Last updated