This guide describes how to track conversion events (such as user signups, newsletter subscriptions, checkouts, and purchases) on your custom landing pages.
When visitors click a shortened URL or an A/B split testing rotator link, JMPY.me automatically appends a unique jmpy_click_id query parameter to the destination URL. By capturing this click ID and reporting events back to the Conversion API, you can attribute conversions to specific variants and calculate statistical significance.
Integration Workflow
Implementing conversion tracking involves three main steps:
- Extract the
jmpy_click_id parameter from the landing page URL.
- Persist the click ID in
localStorage or cookies to ensure it remains available as the visitor navigates your site.
- Report conversion events (e.g.,
signup, purchase) to the JMPY.me Conversion API.
1. Client-Side Tracking Script
Add the following JavaScript code to your landing page and conversion pages. This script automatically handles query parameter parsing, persistence across pages, and event transmission.
Copy-Pasteable JavaScript SDK Snippet
/**
* JMPY Conversion Tracker
*/
const JmpyTracker = {
// Configuration
config: {
apiUrl: 'https://jmpy.me/api/v1/analytics/convert',
storageKey: 'jmpy_click_id',
cookieExpirationDays: 30
},
/**
* Initializes the tracker by checking for the click ID in the URL and saving it.
*/
init() {
const clickId = this.getClickIdFromUrl();
if (clickId) {
this.persistClickId(clickId);
this.cleanUrl(clickId);
}
},
/**
* Extracts the click ID from the query string parameters.
*/
getClickIdFromUrl() {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('jmpy_click_id');
},
/**
* Saves the click ID to localStorage and backup cookie.
*/
persistClickId(clickId) {
try {
window.localStorage.setItem(this.config.storageKey, clickId);
} catch (e) {
console.warn('[JMPY Tracker] localStorage is not accessible. Falling back to cookies.');
}
this.setCookie(this.config.storageKey, clickId, this.config.cookieExpirationDays);
},
/**
* Retrieves the stored click ID from localStorage or cookies.
*/
getStoredClickId() {
let clickId = null;
try {
clickId = window.localStorage.getItem(this.config.storageKey);
} catch (e) {}
if (!clickId) {
clickId = this.getCookie(this.config.storageKey);
}
return clickId;
},
/**
* Cleans the URL by removing the jmpy_click_id parameter (improves aesthetics).
*/
cleanUrl(clickId) {
if (window.history && window.history.replaceState) {
const url = new URL(window.location.href);
url.searchParams.delete('jmpy_click_id');
window.history.replaceState({}, document.title, url.pathname + url.search + url.hash);
}
},
/**
* Track a conversion event.
* @param {string} eventName - Name of the event (e.g. 'signup', 'purchase', 'lead')
* @param {number} [value=0] - Monetary value of the conversion (optional)
* @param {string} [currency='USD'] - 3-letter currency code (optional)
* @param {Object} [metadata={}] - Additional custom metadata (optional)
* @returns {Promise<boolean>}
*/
async track(eventName, value = 0, currency = 'USD', metadata = {}) {
const clickId = this.getStoredClickId();
if (!clickId) {
console.log('[JMPY Tracker] No click ID found. Event not tracked.');
return false;
}
const payload = {
jmpy_click_id: clickId,
event_name: eventName,
value: parseFloat(value) || 0,
currency: currency.toUpperCase(),
metadata: {
...metadata,
url: window.location.href,
referrer: document.referrer
}
};
try {
const response = await fetch(this.config.apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const data = await response.json();
return data.success === true;
} catch (error) {
console.error('[JMPY Tracker] Error reporting conversion:', error);
return false;
}
},
// Helper functions for cookies
setCookie(name, value, days) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
const expires = "; expires=" + date.toUTCString();
document.cookie = name + "=" + (value || "") + expires + "; path=/; SameSite=Lax; Secure";
},
getCookie(name) {
const nameEQ = name + "=";
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
};
// Initialize the tracker immediately on script load
JmpyTracker.init();
2. Practical Examples
To track when a user signs up or submits a contact form:
<!-- Example Form -->
<form id="signup-form">
<input type="email" id="email" required placeholder="Enter your email">
<button type="submit">Sign Up</button>
</form>
<script>
document.getElementById('signup-form').addEventListener('submit', async (e) => {
e.preventDefault();
// Process your registration logic here...
// Track the conversion event in JMPY.me
await JmpyTracker.track('signup', 0, 'USD', {
plan_selected: 'free_trial'
});
// Redirect or show success message
alert('Welcome onboard!');
});
</script>
Example B: Checkout Complete / Purchase
To track a purchase with monetary value:
// On your checkout confirmation/thank-you page
window.addEventListener('DOMContentLoaded', async () => {
// Retrieve purchase details from your e-commerce platform context
const purchaseValue = 49.99;
const orderId = 'ord_998877';
await JmpyTracker.track('purchase', purchaseValue, 'USD', {
transaction_id: orderId,
items_count: 2,
coupon_applied: 'SUMMER20'
});
console.log('[JMPY Tracker] Purchase conversion tracked successfully!');
});
3. Server-to-Server Conversions (Optional)
If you prefer to record conversions directly from your backend (e.g. after database verification or webhook notifications), make a POST request to the Conversion endpoint.
API Specifications
- Endpoint:
POST https://jmpy.me/api/v1/analytics/convert
- Headers:
Content-Type: application/json
- Body Schema:
{
"jmpy_click_id": "clk_1234567890abcdef",
"event_name": "purchase",
"value": 49.00,
"currency": "USD",
"metadata": {
"transaction_id": "tx_998877",
"coupon_code": "SUMMER20"
}
}
Server-side calls do not require API keys or custom headers, as the jmpy_click_id already encodes and maps uniquely to the respective short URL and user account context.