Documentation
How It Works
SignalSyncAds acts as a server-side proxy for your conversion events. Instead of sending data directly from the user's browser to Meta or Google (which is often blocked by ad blockers or iOS privacy changes), we send it to our secure server first.
Our server then authenticates with the ad platforms using the robust Conversions API (CAPI), ensuring 100% signal delivery.
Installation
1. Configure Your Site
Go to your dashboard to add your domain and connect your ad accounts. You'll need your Meta Pixel ID/Access Token and Google Ads Customer ID/Conversion Token.
2. Add the Snippet
Place the generated script tag in the <head> section of your website. Copy your personalized snippet from the dashboard:
<script>
(function (window, document) {
if (window.SSA && window.SSA.__initialized) return;
var STORAGE_KEY = '__ssa_queue__';
var MAX_RETRIES = 3;
var BATCH_SIZE = 5;
var FLUSH_INTERVAL = 400;
function uuid() {
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0;
var v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
function safeParse(val, fallback) {
try { return JSON.parse(val); } catch (e) { return fallback; }
}
var SSA = {
__initialized: true,
siteId: 'YOUR_SITE_ID', // From your dashboard
endpoint: 'https://signalsyncads.vercel.app/api/track',
consent: true,
debug: false,
queue: safeParse(localStorage.getItem(STORAGE_KEY), []),
isSending: false,
flushTimer: null,
setConsent: function (value) { this.consent = !!value; },
enableDebug: function () { this.debug = true; console.info('[SSA] Debug mode enabled'); },
_persist: function () {
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(this.queue)); } catch (e) {}
},
track: function (eventName, data) {
if (!this.consent || !eventName) return;
var payload = {
id: uuid(),
siteId: this.siteId,
event_name: eventName,
timestamp: Date.now(),
url: window.location.href,
referrer: document.referrer || null,
retries: 0,
data: data || {}
};
this.queue.push(payload);
this._persist();
this._scheduleFlush();
},
_scheduleFlush: function () {
if (this.flushTimer) return;
var self = this;
this.flushTimer = setTimeout(function () {
self.flushTimer = null;
self._flush();
}, FLUSH_INTERVAL);
},
_sendBatch: function (batch, useBeacon) {
var body = JSON.stringify(batch);
if (useBeacon && navigator.sendBeacon) {
var blob = new Blob([body], { type: 'application/json' });
return navigator.sendBeacon(this.endpoint, blob);
}
return fetch(this.endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
keepalive: true,
body: body
});
},
_flush: function (forceBeacon) {
if (this.isSending || !this.queue.length) return;
this.isSending = true;
var batch = this.queue.slice(0, BATCH_SIZE);
var self = this;
var result = this._sendBatch(batch, forceBeacon);
function success() { self.queue.splice(0, batch.length); self._persist(); }
function failure() {
for (var i = 0; i < batch.length; i++) batch[i].retries++;
self.queue = batch.concat(self.queue.slice(batch.length))
.filter(function (e) { return e.retries <= MAX_RETRIES; });
self._persist();
}
if (result === true) { success(); self.isSending = false; return; }
Promise.resolve(result).then(success).catch(failure).finally(function () {
self.isSending = false;
if (self.queue.length) self._scheduleFlush();
});
}
};
window.SSA = SSA;
window.addEventListener('visibilitychange', function () {
if (document.visibilityState === 'hidden') SSA._flush(true);
});
window.addEventListener('beforeunload', function () { SSA._flush(true); });
if (SSA.queue.length) SSA._scheduleFlush();
})(window, document);
</script>
<!-- Example: Track a conversion -->
<script>
SSA.track('Purchase', { value: 99.99, currency: 'USD' });
</script>Testing
Use the "Send Test Conversion" button in the onboarding wizard to verify that events are reaching our servers and being forwarded correctly.
Troubleshooting Tips
- Ensure your tokens are valid and have permissions.
- Check that the Site ID in your snippet matches your dashboard.
- Verify that you aren't blocking our script in your CSP settings.