Phone Call Tracking
SendSquared provides phone call tracking capabilities that allow you to monitor and track calls from various sources such as PPC campaigns. This guide explains how to set up and use the phone flip script for call tracking.
Accessing Phone Flip Script
You can access the Phone Flip Script in the SendSquared platform by following these steps:
- Navigate to Global Settings
- Select Integration Settings
- Choose Phone Flip
Installing the Phone Flip Script
The phone flip script needs to be installed on your website to enable call tracking functionality. This script allows you to create campaigns and add rotating numbers in your URL to track phone calls from PPC or any other source.
Basic Installation
Copy and paste the following code into your website:
<script src="https://app-api.sendsquared.com/tracking/v1/bse-analytics-es3.js"></script>
<script src="https://app-api.sendsquared.com/phone-tracking/v1/phone-tracking.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded',async function(event){
S2CallTracking('your-uuid-here');
});
</script>
Using the Phone Flip Feature
Once installed on your website, any phone number listed in Global Settings → Phone Numbers and Campaign Settings can be used for tracking by appending a query parameter to the URL.
For your protection and to prevent phishing attacks, the phone flip feature includes built-in security measures:
- Verified Phone Numbers: Only phone numbers that are registered and verified in your SendSquared account can be displayed
- Domain Validation: The script will only work on domains that have been pre-approved and associated with your account
- Account Binding: Each tracking script is uniquely tied to your account UUID, preventing unauthorized use
These safeguards ensure that malicious actors cannot use your tracking infrastructure to display unauthorized phone numbers or deploy phishing campaigns using your domain reputation.
URL Parameter Format
Add the following query parameter to your URL:
?s2number=%2B16122904467
Where:
%2B
is the URL encoding for the plus sign (+
)16122904467
is the phone number in format 1 (612) 290-4467, or whichever phone number you want to display on the website
📞 Phone Tracking URL Builder
Enter a phone number and your website URL to generate a trackable link.
Persistence
When a visitor arrives via a URL with the phone number parameter:
- A cookie is installed on the client's browser
- The phone number change will persist for up to 30 days after the initial visit
Advanced Configuration
You can customize how the phone flip script works with additional settings:
Phone Flip Generator with Custom Options
<script src="https://app-api.sendsquared.com/tracking/v1/bse-analytics-es3.js"></script>
<script src="https://app-api.sendsquared.com/phone-tracking/v1/phone-tracking.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded',async function(event){
S2CallTracking('your-uuid-here', {
classRef:'s2-phone',
pattern:'1 (###) ###-####',
sourcePattern:'/(\b1[-.\s]?)?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\b/g',
clickToCall: true,
debugMode: false,
formContainerSelectors: 'main, #content, .content, #app'
});
});
</script>
Customization Options
You can modify the following settings:
-
CSS class (
classRef:'s2-phone'
): This allows you to customize the class used to find phone numbers on your webpage that will be changed. -
Pattern (
pattern:'1 (###) ###-####'
): This is the format used to replace the number on your webpage. -
Read Pattern (
sourcePattern:'/(\b1[-.\s]?)?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\b/g'
): This is the regular expression pattern used to read phone numbers from the inner HTML of elements on your page. -
Click to Call (
clickToCall: true
): When enabled, tracks click-to-call events separately from regular link clicks for more detailed analytics. -
Debug Mode (
debugMode: true
): Enables detailed console logging for troubleshooting (see Debug Mode section below). -
Form Container Selectors (
formContainerSelectors: 'main, #content'
): CSS selectors for containers where forms are likely to appear, optimizing form tracking performance.
The phone tracking script automatically updates tel:
links when replacing phone numbers. Both the visible text and the href
attribute are kept in sync with the tracked number, ensuring click-to-call functionality works correctly on mobile devices.
🛠️ Phone Flip Customization Playground
Configure how the phone flip script finds and formats phone numbers on your website.
Configuration Options
Example HTML Transformation
<div class="contact-info">
<p>Call us at: <span class="s2-phone">1-800-555-1234</span></p>
<p>Support: <span class="s2-phone">(555) 123-4567</span></p>
<div class="s2-phone">1.888.999.0000</div>
</div>
<div class="contact-info">
<p>Call us at: <span class="s2-phone">1 (612) 290-4467</span></p>
<p>Support: <span class="s2-phone">1 (612) 290-4467</span></p>
<div class="s2-phone">1 (612) 290-4467</div>
</div>
When URL has ?s2number=%2B16122904467
Debug Mode
Debug mode provides detailed console logging to help you troubleshoot phone tracking implementation and monitor GA4 event tracking in real-time.
Enabling Debug Mode
S2CallTracking('your-uuid-here', {
debugMode: true // Enable detailed console logging
});
Debug Output Examples
When debug mode is enabled, you'll see color-coded console logs for different operations:
1. Initialization Output
[S2 Phone Tracking] Initialization
Configuration:
Token: ✓ Set
Class Reference: s2-phone
Click to Call: Enabled
Debug Mode: Enabled
Cookie Domain: Default
Number Pattern: 1 (###) ###-####
Environment:
Current URL: https://example.com/landing?s2number=%2B16125551234
Referrer: https://google.com
User Agent: Chrome/120.0...
Analytics Method: gtag
2. Phone Number Rotation
[S2 Phone Tracking] Rotating Phone Number
Query Parameter: %2B16125551234
Using Token: Yes
API Response: {success: true, numbers: [...]}
3. GA4 Event Tracking
[S2 Phone Tracking] GA Event: phone_number_rotated
Event Data: {
event_category: "Phone Tracking",
tracking_source: "SendSquaredPhoneFlip",
tracking_phone_number: "+16125551234",
traffic_source: "google_ads",
is_google_ads: true
}
Timestamp: 2025-01-25T10:30:45.123Z
Analytics Method: gtag
✓ GA Event Sent via gtag()
4. Form Tracking
[S2 Phone Tracking] Form Tracking Initialization
Forms Found: 3
1. contact-form
2. newsletter-signup
3. demo-request
[S2 Phone Tracking] Tracking new form: {
id: "contact-form",
className: "main-contact",
action: "/submit",
fields: 5
}
5. API Calls
[S2 Phone Tracking] API Call
Endpoint: https://app-api.sendsquared.com/v1/public/phone-list
API Key: Provided
API Success: 4 phone numbers retrieved
Common Debug Scenarios
Checking if GA4 is Available
// In browser console with debug mode on
S2CallTracking('your-uuid-here', { debugMode: true });
// Look for:
// "Analytics Method: gtag" - Direct GA4 implementation
// "Analytics Method: dataLayer" - GTM implementation
// "⚠ No GA/GTM implementation found" - No analytics detected
Verifying Form Tracking
// Enable debug mode to see all forms being tracked
S2CallTracking('your-uuid-here', {
debugMode: true,
formContainerSelectors: 'main, #app'
});
// Submit a form to see the GA4 event:
// [S2 Phone Tracking] GA Event: form_submission_with_phone_tracking
Troubleshooting Cookie Persistence
S2CallTracking('your-uuid-here', { debugMode: true });
// Check for cookie loading:
// "[S2 Phone Tracking] Loading from Cookie"
// "Cookie Data: {token: '+16125551234', trackingPhoneNumber: '+16125551234'}"
Debug Mode Best Practices
- Development Only: Always disable debug mode in production to avoid console clutter
- Browser DevTools: Use Chrome DevTools filters to show only S2 Phone Tracking logs
- Event Rate Limiting: Debug mode shows when events are rate-limited (1 second between same events)
- Error Tracking: All API errors and validation failures are logged with detailed messages
GA4 Event Tracking
SendSquared's phone tracking automatically integrates with Google Analytics 4 (GA4) to provide comprehensive tracking of all phone-related interactions. Events are sent automatically when GA4 or Google Tag Manager is detected on your page.
Automatic Event Detection
The script automatically detects your GA4 implementation method:
- Direct GA4 (
gtag
): When you have GA4 installed directly on your site - Google Tag Manager (
dataLayer
): When using GTM to manage GA4 - No Analytics: Script continues to function but events aren't sent
GA4 Events Tracked
The following events are automatically tracked and sent to GA4:
Event Name | Description | When Fired | Key Parameters |
---|---|---|---|
phone_tracking_initialized | Script successfully initialized | Page load | has_cookie , has_query_param , traffic_source , analytics_method |
phone_number_loaded_from_cookie | Number loaded from existing cookie | Cookie detected | traffic_source , is_google_ads |
phone_number_rotated | New number set from URL parameter | URL parameter processed | source , traffic_source , is_google_ads |
phone_number_displayed | Number successfully replaced on page | DOM updated | formatted_number , class_ref , traffic_source |
form_submission_with_phone_tracking | Form submitted with tracking active | Form submission | form_id , form_action , form_fields , traffic_source |
phone_click_to_call | Click-to-call link clicked | Tel link clicked (when clickToCall: true ) | formatted_number , element_class |
phone_link_clicked | Phone link clicked | Tel link clicked (when clickToCall: false ) | formatted_number , element_class |
phone_rotation_error | Error during number rotation | API or validation error | error_message , traffic_source |
Event Parameters
All events include these standard parameters:
{
event_category: "Phone Tracking",
tracking_source: "SendSquaredPhoneFlip",
tracking_phone_number: "+16125551234", // or "not_set" if no number
// Plus event-specific parameters
}
Understanding Click Event Types
Both phone_click_to_call
and phone_link_clicked
events track clicks on tel:
phone links, but serve different analytics purposes. The event fired depends solely on your clickToCall
configuration setting.
When to Use Each Event Type
Use phone_click_to_call
(clickToCall: true) when:
- You consider phone link clicks as conversion events
- You want to track high-intent user actions
- You're running call-focused campaigns
- You need to measure call initiation attempts for ROI calculations
Use phone_link_clicked
(clickToCall: false) when:
- You want to track general engagement metrics
- Phone clicks are informational (users might copy the number)
- You need to distinguish between browsing behavior and conversion intent
- You're analyzing user interaction patterns
Implementation Examples
Example 1: E-commerce Site with Sales Focus
// Track clicks as high-intent conversion actions
S2CallTracking('your-uuid-here', {
clickToCall: true, // Fires 'phone_click_to_call' events
classRef: 's2-phone'
});
// In GA4, set up conversion tracking:
// 1. Mark 'phone_click_to_call' as a conversion event
// 2. Assign conversion value (e.g., average call value)
// 3. Use for Google Ads conversion optimization
Example 2: Service Directory with Multiple Listings
// Track clicks as engagement metrics
S2CallTracking('your-uuid-here', {
clickToCall: false, // Fires 'phone_link_clicked' events (default)
classRef: 's2-phone'
});
// In GA4, use for engagement analysis:
// 1. Track which listings get most phone interactions
// 2. Analyze user behavior flow
// 3. Don't count as conversions (users comparing options)
Example 3: Different Tracking for Different Pages
// Landing pages - track as conversions
if (window.location.pathname.includes('/landing/')) {
S2CallTracking('your-uuid-here', {
clickToCall: true, // High intent from ad traffic
debugMode: false
});
}
// Support pages - track as engagement
else if (window.location.pathname.includes('/support/')) {
S2CallTracking('your-uuid-here', {
clickToCall: false, // Users might just copy number
debugMode: false
});
}
GA4 Configuration Differences
For phone_click_to_call
Events:
// GA4 Setup:
// Event name: phone_click_to_call
// Mark as: Conversion
// Use in: Google Ads conversion tracking
// Audience: High-intent users
// Typical value: $50-200 per call
For phone_link_clicked
Events:
// GA4 Setup:
// Event name: phone_link_clicked
// Mark as: Engagement metric
// Use in: Behavior flow analysis
// Audience: Engaged users
// Typical value: Not assigned
Testing Your Configuration
// Enable debug mode to verify which event fires
S2CallTracking('your-uuid-here', {
clickToCall: true, // or false
debugMode: true
});
// Click a phone link and check console:
// [S2 Phone Tracking] Added click tracking: phone_click_to_call
// OR
// [S2 Phone Tracking] Added click tracking: phone_link_clicked
Important: Both events track the exact same user action (clicking a tel:
link). The only difference is the event name sent to GA4, which allows you to handle them differently in your analytics and conversion tracking strategy.
Traffic Source Detection
The script automatically detects and includes traffic source information:
- Google Ads Detection: Checks for
gclid
,gbraid
,wbraid
parameters - UTM Parameters: Reads
utm_source
when available - Referrer: Falls back to referrer domain or "direct"
Viewing Events in GA4
Real-Time Reports
- Go to GA4 → Reports → Real time
- Look for custom events starting with
phone_
- Click on an event to see parameters
DebugView
- Enable debug mode in your script:
debugMode: true
- Go to GA4 → Configure → DebugView
- See events firing in real-time with all parameters
Custom Reports
Create custom reports in GA4 to track:
- Phone tracking conversion rate by traffic source
- Form submissions with phone tracking
- Click-to-call interactions by page
Example GA4 Implementation
// Basic setup with GA4 tracking
S2CallTracking('your-uuid-here', {
classRef: 's2-phone',
clickToCall: true, // Track click-to-call separately
debugMode: false // Enable for GA4 DebugView
});
// Events will automatically flow to GA4 if gtag is present
Verifying GA4 Integration
// Check if GA4 is detected (in console)
if (typeof gtag === 'function') {
console.log('✓ GA4 detected - events will be tracked');
} else if (Array.isArray(dataLayer)) {
console.log('✓ GTM detected - events will be tracked');
} else {
console.log('✗ No GA4/GTM found - events won't be sent');
}
Form Processing with GA4
SendSquared automatically tracks form submissions when phone tracking is active, providing valuable attribution data for lead generation.
How Form Tracking Works
- Automatic Detection: All forms on the page are automatically detected
- Dynamic Form Support: New forms added via JavaScript are tracked
- Performance Optimized: Uses MutationObserver with debouncing
- No Duplicate Tracking: Each form is tracked only once
Form Submission Event Data
When a form is submitted, the following data is sent to GA4:
{
event: "form_submission_with_phone_tracking",
event_category: "Phone Tracking",
form_id: "contact-form", // Form ID or class name
form_action: "/submit", // Form action URL
form_fields: "name,email,phone,message", // Comma-separated field names
tracking_phone_number: "+16125551234", // Current tracking number
traffic_source: "google_ads", // Detected traffic source
is_google_ads: true, // Google Ads detection
page_url: "https://example.com/contact",
timestamp: "2025-01-25T10:30:45.123Z"
}
Optimizing Form Detection
For better performance on sites with many dynamic elements, specify where forms typically appear:
S2CallTracking('your-uuid-here', {
formContainerSelectors: '#main-content, .form-wrapper, [data-form-container]'
});
Form Tracking Examples
Contact Form with Attribution
<form id="contact-form" action="/submit">
<input name="name" type="text" required>
<input name="email" type="email" required>
<input name="phone" type="tel">
<textarea name="message"></textarea>
<button type="submit">Submit</button>
</form>
<script>
// Form submission will trigger GA4 event with:
// - form_id: "contact-form"
// - form_fields: "name,email,phone,message"
// - tracking_phone_number: (current tracked number)
// - traffic_source: (detected source)
</script>
Dynamic Form Support
// Forms added dynamically are automatically tracked
const newForm = document.createElement('form');
newForm.id = 'dynamic-form';
newForm.innerHTML = '<input name="email"><button>Submit</button>';
document.body.appendChild(newForm);
// Automatically tracked within 100ms
Creating GA4 Conversions
To track form submissions as conversions in GA4:
- Go to GA4 → Configure → Events
- Find
form_submission_with_phone_tracking
- Toggle "Mark as conversion"
- Create audiences based on
traffic_source
oris_google_ads
parameters
Google Tag Manager vs Direct GA4 Implementation
SendSquared supports both implementation methods seamlessly:
Direct GA4 Implementation
When GA4 is installed directly on your site:
<!-- Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>
<!-- SendSquared Phone Tracking -->
<script src="https://app-api.sendsquared.com/tracking/v1/bse-analytics-es3.js"></script>
<script src="https://app-api.sendsquared.com/phone-tracking/v1/phone-tracking.min.js"></script>
<script>
// Events sent via gtag() function
S2CallTracking('your-uuid-here');
</script>
How it works: Events are sent directly using gtag('event', eventName, parameters)
Google Tag Manager Implementation
When using GTM to manage GA4:
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX');</script>
<!-- SendSquared Phone Tracking -->
<script src="https://app-api.sendsquared.com/tracking/v1/bse-analytics-es3.js"></script>
<script src="https://app-api.sendsquared.com/phone-tracking/v1/phone-tracking.min.js"></script>
<script>
// Events sent via dataLayer.push()
S2CallTracking('your-uuid-here');
</script>
How it works: Events are pushed to dataLayer: dataLayer.push({event: eventName, ...parameters})
GTM Configuration for Phone Tracking Events
To capture SendSquared events in GTM:
-
Create Custom Event Triggers:
- Trigger Type: Custom Event
- Event name:
phone_*
(regex matching) - Or create specific triggers for each event
-
Create Variables for Parameters:
Variable Name: Phone Tracking Number
Variable Type: Data Layer Variable
Data Layer Variable Name: tracking_phone_number -
Create GA4 Event Tags:
Tag Type: Google Analytics: GA4 Event
Event Name: {{Event}}
Event Parameters:
- tracking_phone_number: {{Phone Tracking Number}}
- traffic_source: {{Traffic Source}}
- form_id: {{Form ID}}
Comparison Table
Feature | Direct GA4 | Google Tag Manager |
---|---|---|
Setup Complexity | Simple | More complex |
Event Control | Automatic | Full control via GTM |
Custom Parameters | Pre-defined | Fully customizable |
Debugging | GA4 DebugView | GTM Preview + GA4 DebugView |
Event Filtering | In GA4 only | Can filter in GTM |
Performance | Direct send | Extra dataLayer step |
Flexibility | Limited | Very flexible |
Best Practices
- Direct GA4: Best for simple implementations where you want automatic tracking
- GTM: Best when you need custom logic, filtering, or integration with other tools
- Testing: Always use debug mode to verify events are flowing correctly
- Documentation: Document which events trigger which conversions for your team
Migrating from Other Platforms
All phone number porting from CallRail, Invoca, or other providers is handled by SendSquared's support team. Our team manages the entire porting process to ensure a smooth transition. Please review our comprehensive porting guide and contact support to begin.
Migrating from CallRail
SendSquared provides a complete replacement for CallRail's call tracking functionality with additional marketing automation features. Here's how to migrate:
Step 1: Export Your CallRail Data
- Log into CallRail and export:
- Phone numbers list
- Tracking sources/campaigns
- Historical call data (CSV export)
- Document your current tracking setup:
- Which numbers track which campaigns
- Dynamic number insertion settings
- Routing rules
Step 2: Set Up SendSquared Phone Tracking
-
Port Your Phone Numbers
- Contact SendSquared support team to initiate number porting
- Our team will handle the entire porting process for you
- See our comprehensive porting guide for details
- Important: Do NOT disconnect your CallRail service until porting is complete
-
Replace CallRail's JavaScript
Remove CallRail's swap script:
<!-- Remove this -->
<script type="text/javascript" src="//cdn.callrail.com/companies/123456789/swap.js"></script>Replace with SendSquared:
<!-- Add this -->
<script src="https://app-api.sendsquared.com/tracking/v1/bse-analytics-es3.js"></script>
<script src="https://app-api.sendsquared.com/phone-tracking/v1/phone-tracking.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded',async function(event){
S2CallTracking('your-uuid-here');
});
</script> -
Update Campaign URLs
- CallRail format:
?callrail_number=555-1234
- SendSquared format:
?s2number=%2B15551234
- Update all PPC campaigns, email links, and QR codes
- CallRail format:
Step 3: Advantages After Migration
- Unified Platform: Phone tracking + SMS + email automation in one system
- Advanced Attribution: Multi-touch attribution across all channels
- Built-in CRM: No need for separate CRM integration
- Automated Follow-ups: Trigger SMS/email sequences from phone calls
Migrating from Invoca
SendSquared offers a streamlined alternative to Invoca's enterprise call tracking with simpler implementation and transparent pricing.
Step 1: Audit Your Invoca Setup
- Document your Invoca configuration:
- RingPools and number pools
- Signal AI rules and custom parameters
- Integration webhooks
- Export data:
- Phone numbers inventory
- Campaign mappings
- Call recordings (if needed)
Step 2: Port Numbers & Set Up SendSquared
-
Port Your Phone Numbers
- Contact SendSquared support team to initiate number porting from Invoca
- Our team manages the complete porting process
- Review our porting guide for timeline expectations
- Critical: Keep your Invoca service active during porting
-
Dynamic Number Pools
Invoca RingPool equivalent:
// Invoca approach (complex)
Invoca.PNAPI.run('RingPool', 'UniqueID', options);
// SendSquared approach (simple)
S2CallTracking('your-uuid-here', {
classRef: 's2-phone',
pattern: '1 (###) ###-####'
}); -
Campaign Attribution
- Invoca: Complex promo number mapping
- SendSquared: Simple URL parameter (
?s2number=
) - No need for separate campaign IDs or pool management
-
Convert Invoca Tags
Replace Invoca's tag:
<!-- Remove Invoca -->
<script src="//solutions.invocacdn.com/js/invoca-latest.min.js"></script>
<!-- Add SendSquared -->
<script src="https://app-api.sendsquared.com/tracking/v1/bse-analytics-es3.js"></script>
<script src="https://app-api.sendsquared.com/phone-tracking/v1/phone-tracking.min.js"></script>
Step 3: Key Improvements
- Simpler Implementation: No complex RingPools or JavaScript APIs
- Transparent Pricing: No hidden fees or complex pricing tiers
- Faster Setup: Minutes vs weeks for implementation
- All-in-One Platform: Includes SMS, email, and automation
- No Minimum Commits: Pay for what you use, scale as needed
Migration Checklist
Pre-Migration
- Audit current phone numbers and ownership
- Export historical data from current platform
- Document current tracking logic and rules
- List all integrated systems and webhooks
- Contact SendSquared support to initiate porting
- Plan migration timing (low-traffic period recommended)
- Review porting documentation
During Migration
- Work with SendSquared support team on number porting
- Keep existing service active until porting completes
- Configure domain whitelist with support team
- Install SendSquared tracking script
- Test with demo parameters before going live
- Update all campaign URLs with new parameters
- Verify tracking on staging environment
Post-Migration
- Monitor first 24 hours closely
- Verify all numbers are swapping correctly
- Check attribution data is flowing
- Remove old tracking scripts
- Cancel previous service (after confirming success)
- Set up automated workflows for call follow-ups
Quick Comparison
Feature | CallRail/Invoca | SendSquared |
---|---|---|
Setup Time | Days/Weeks | Minutes |
JavaScript Complexity | Complex APIs | Single function call |
Number Management | Manual pools | Automatic via URL |
SMS Integration | Separate service | Built-in |
Email Automation | Requires integration | Native feature |
Minimum Contract | Often required | Annual |
Attribution Model | Call-focused | Omnichannel |
CRM Features | Limited/Integration | Full CRM included |
Support | Tiered | Included for all |
Common Migration Questions
Q: Can I keep my existing tracking numbers? A: Yes, SendSquared support will handle the complete porting process for you. See our porting guide for details.
Q: How long does migration take? A: Technical implementation takes 1-2 hours. Number porting typically takes 7-10 business days but can vary by carrier. Our support team will provide timeline estimates.
Q: Will I lose historical data? A: No, export your historical data before migration. SendSquared starts fresh tracking from implementation date.
Q: Can I run both systems in parallel? A: Yes, you can test SendSquared on specific pages while keeping your existing system on others during transition.
How-To Guides & Tutorials
How to Replace Phone Numbers on Specific Pages Only
Follow these steps to control which pages display tracked phone numbers:
Step 1: Identify Target Pages
Decide which pages should show tracked numbers (e.g., landing pages, PPC-specific pages).
Step 2: Conditional Script Loading
<!-- Option 1: Load script only on specific pages -->
<!-- Add this to your landing page template only -->
<script src="https://app-api.sendsquared.com/tracking/v1/bse-analytics-es3.js"></script>
<script src="https://app-api.sendsquared.com/phone-tracking/v1/phone-tracking.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded',async function(event){
// Check if we're on a landing page
if (window.location.pathname.includes('/landing/') ||
window.location.pathname.includes('/campaign/')) {
S2CallTracking('your-uuid-here');
}
});
</script>
Step 3: Use CSS Classes for Selective Replacement
<!-- Option 2: Use specific CSS classes -->
<!-- Mark only certain phone numbers for replacement -->
<div class="track-this-phone">Call us: 1-800-555-1234</div>
<div>Support (not tracked): 1-800-555-1234</div>
<script>
document.addEventListener('DOMContentLoaded',async function(event){
S2CallTracking('your-uuid-here', {
classRef:'track-this-phone', // Only replaces numbers in elements with this class
});
});
</script>
How to Test Number Swapping with Demo Parameters
Test your phone tracking implementation without affecting live visitors:
Step 1: Set Up Test Numbers
- Add test phone numbers in Global Settings → Phone Numbers and Campaign Settings
- Example test numbers:
- Test Line 1: +16125551111
- Test Line 2: +16125552222
Step 2: Create Test URLs
# Production URL
https://yoursite.com/contact
# Test URL with demo parameter
https://yoursite.com/contact?s2number=%2B16125551111&test=true
# Test multiple campaigns
https://yoursite.com/landing-a?s2number=%2B16125551111
https://yoursite.com/landing-b?s2number=%2B16125552222
Step 3: Validate in Browser DevTools
- Open Chrome DevTools (F12)
- Go to Application → Cookies
- Look for the
s2_phone
cookie - Verify the test number is stored
- Navigate to other pages to confirm persistence
Step 4: Use Console for Debugging
// Add this to your script for debug mode
document.addEventListener('DOMContentLoaded',async function(event){
const urlParams = new URLSearchParams(window.location.search);
const isTest = urlParams.get('test') === 'true';
if (isTest) {
console.log('📞 Phone Tracking Test Mode Active');
console.log('Original numbers:', document.querySelectorAll('.s2-phone'));
}
S2CallTracking('your-uuid-here');
if (isTest) {
setTimeout(() => {
console.log('Replaced numbers:', document.querySelectorAll('.s2-phone'));
}, 1000);
}
});
How to Troubleshoot When Script Isn't Firing
Systematic approach to diagnose phone tracking issues:
Step 1: Verify Script Loading
// Open browser console and check:
console.log(typeof S2CallTracking); // Should output: "function"
// If undefined, scripts aren't loading properly
Step 2: Check for JavaScript Errors
- Open browser console (F12)
- Look for red error messages
- Common errors:
- "S2CallTracking is not defined" → Scripts not loaded
- "Authentication is required" → Missing API key (x-api-key header)
- "Origin or referer is required" → Missing origin/referer headers
- "Invalid token or domain" → API key not recognized or domain not whitelisted
Step 3: Validate DOM Ready
// Ensure DOM is fully loaded before script runs
console.log('DOM State:', document.readyState);
// Add loading check
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
S2CallTracking('your-uuid-here');
});
} else {
// DOM already loaded
S2CallTracking('your-uuid-here');
}
Step 4: Test with Manual Trigger
// Try running manually in console
S2CallTracking('your-uuid-here', {
classRef: 'body', // Target all numbers in body
pattern: '# (###) ###-####'
});
Code Recipes & Snippets
Format Phone Numbers as (###) ###-####
// Standard US format without country code
S2CallTracking('your-uuid-here', {
pattern: '(###) ###-####',
sourcePattern: '/\\(?([0-9]{3})\\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})/g'
});
Format with Country Code: +1 (###) ###-####
// International format with US country code
S2CallTracking('your-uuid-here', {
pattern: '+1 (###) ###-####',
sourcePattern: '/(\\+?1[-. ]?)?\\(?([0-9]{3})\\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})/g'
});
Replace Numbers Only in Footer
// Target footer phone numbers exclusively
S2CallTracking('your-uuid-here', {
classRef: 'footer-phone', // Add this class to footer phone elements
});
// Alternative: Use querySelector approach
document.addEventListener('DOMContentLoaded', function() {
// First run normal tracking
S2CallTracking('your-uuid-here', {
classRef: 'hidden-element-that-doesnt-exist' // Disable default
});
// Then target footer specifically
const footerPhones = document.querySelectorAll('footer .phone-number');
footerPhones.forEach(el => {
el.classList.add('s2-phone');
});
// Re-run on footer elements
S2CallTracking('your-uuid-here');
});
Replace Numbers in Multiple Sections
// Target header, footer, and sidebar
S2CallTracking('your-uuid-here', {
classRef: 'trackable-phone'
});
// Add class to multiple sections
document.querySelectorAll('header .phone, footer .phone, .sidebar .phone')
.forEach(el => el.classList.add('trackable-phone'));
Fallback Number if Parameter Missing
// Provide default number when no URL parameter exists
document.addEventListener('DOMContentLoaded', function() {
const urlParams = new URLSearchParams(window.location.search);
let phoneParam = urlParams.get('s2number');
// If no parameter, add default
if (!phoneParam) {
const defaultNumber = '+16125550000'; // Your default tracking number
const newUrl = new URL(window.location);
newUrl.searchParams.set('s2number', defaultNumber);
// Optional: Update URL without reload
history.replaceState({}, '', newUrl);
}
S2CallTracking('your-uuid-here');
});
Different Numbers for Mobile vs Desktop
// Show different numbers based on device
document.addEventListener('DOMContentLoaded', function() {
const isMobile = window.matchMedia('(max-width: 768px)').matches;
const urlParams = new URLSearchParams(window.location.search);
// Override parameter for mobile users
if (isMobile && !urlParams.get('mobile_override')) {
const mobileNumber = '+16125559999'; // Mobile-specific number
urlParams.set('s2number', mobileNumber);
urlParams.set('mobile_override', 'true');
const newUrl = new URL(window.location);
newUrl.search = urlParams.toString();
history.replaceState({}, '', newUrl);
}
S2CallTracking('your-uuid-here');
});
Test in Staging vs Production
// Environment-specific configuration
const config = {
staging: {
uuid: 'staging-uuid-here',
testNumbers: ['+16125551111', '+16125552222'],
debug: true
},
production: {
uuid: 'production-uuid-here',
testNumbers: [],
debug: false
}
};
const env = window.location.hostname.includes('staging') ? 'staging' : 'production';
const settings = config[env];
if (settings.debug) {
console.log('🔧 Phone Tracking Environment:', env);
}
S2CallTracking(settings.uuid, {
debug: settings.debug
});
Conceptual Overview
How SendSquared Phone Tracking Works Under the Hood
The Architecture
SendSquared's phone tracking system operates through a sophisticated client-side JavaScript implementation that ensures security while providing flexibility:
-
UUID Authentication
- Each account receives a unique UUID during setup
- This UUID is cryptographically tied to your account
- The tracking script validates the UUID against SendSquared's servers
- Invalid UUIDs are rejected, preventing unauthorized usage
-
Domain Validation Process
- Number Replacement Flow
- Script scans DOM for elements matching the specified class/pattern
- Extracts phone numbers using RegEx pattern matching
- Checks URL parameters for replacement number
- Validates replacement number against account's approved numbers
- Replaces numbers in DOM if all validations pass
- Stores preference in cookie for persistence
Security & Anti-Spoofing Measures
Why Spoofing is Prevented:
-
Three-Layer Validation
- Layer 1: UUID must match an active SendSquared account
- Layer 2: Domain must be pre-registered for that UUID
- Layer 3: Phone number must be verified in account settings
-
Request Validation
// Simplified representation of validation flow
Request: {
uuid: 'abc-123',
domain: 'example.com',
number: '+16125551234'
}
// Server validates uuid + domain combination -
Rate Limiting
- API calls are rate-limited per UUID
- Suspicious patterns trigger automatic blocking
- Failed validation attempts are logged
How SendSquared Chooses Which Number to Show
Decision Tree Logic
Cookie Persistence Logic
-
Initial Visit with Parameter
- User arrives via
?s2number=%2B16125551234
- Cookie set:
s2_phone=+16125551234
- Expiry: 30 days from creation
- Domain: Current domain and subdomains
- User arrives via
-
Subsequent Visits
- No URL parameter needed
- Script reads cookie value
- Continues showing tracked number
- Cookie expiry extends on each visit
-
Parameter Override
- New parameter overrides existing cookie
- Cookie updated with new number
- Useful for A/B testing different numbers
Invalid Number Handling
When an invalid number is passed:
- Validation Fails: Number not in approved list
- Fallback: Original page numbers remain unchanged
- Logging: Failed attempt logged for security monitoring
- No Cookie: Invalid numbers are never stored
- Console Warning: Debug message if debug mode enabled
Troubleshooting Playbook
Phone Number Not Swapping
Diagnostic Steps
-
Check Class Reference
// In browser console:
document.querySelectorAll('.s2-phone').length
// Should return > 0 if elements exist
// Check your configuration:
console.log('Looking for class:', 'your-class-here'); -
Verify RegEx Pattern
// Test your pattern:
const testNumbers = [
'(612) 555-1234',
'612-555-1234',
'6125551234',
'+1 612 555 1234'
];
const pattern = /(\b1[-.\s]?)?\(?([0-9]{3})\)?[-.\s]?([0-9]{3})[-.\s]?([0-9]{4})\b/g;
testNumbers.forEach(num => {
console.log(`${num}: ${pattern.test(num)}`);
}); -
Domain Validation Check
// Verify domain is authorized:
console.log('Current domain:', window.location.hostname);
console.log('Protocol:', window.location.protocol);
// Should be https:// for production -
Number Format in URL
// Check URL encoding:
const urlParams = new URLSearchParams(window.location.search);
console.log('Raw parameter:', urlParams.get('s2number'));
console.log('Decoded:', decodeURIComponent(urlParams.get('s2number') || ''));
Wrong Format Showing
Pattern Value Issues
-
Diagnosis
// Current configuration test:
const currentPattern = '1 (###) ###-####';
const testNumber = '6125551234';
// Check what format is being applied:
console.log('Input:', testNumber);
console.log('Pattern:', currentPattern);
console.log('Expected: 1 (612) 555-1234'); -
Common Pattern Fixes
// Problem: Extra spaces
pattern: '1(###)###-####' // ❌ No spaces
pattern: '1 (###) ###-####' // ✅ Correct spacing
// Problem: Wrong placeholder
pattern: '1 (XXX) XXX-XXXX' // ❌ Wrong placeholder
pattern: '1 (###) ###-####' // ✅ Use # for digits
Script Not Firing
Browser Console Checks
-
Check Script Loading Order
<!-- ✅ Correct order -->
<script src=".../bse-analytics-es3.js"></script>
<script src=".../phone-tracking.min.js"></script>
<script>S2CallTracking('uuid');</script>
<!-- ❌ Wrong order -->
<script>S2CallTracking('uuid');</script>
<script src=".../phone-tracking.min.js"></script> -
Content Security Policy
// Check for CSP errors:
// Look for: "Refused to load script... Content Security Policy"
// Fix: Add to CSP header
Content-Security-Policy: script-src 'self' https://app-api.sendsquared.com; -
Ad Blockers
// Test if tracking script is blocked:
if (typeof S2CallTracking === 'undefined') {
console.warn('Phone tracking may be blocked by ad blocker');
// Implement fallback or notify user
}
Cookie Not Persisting
-
Check Cookie Settings
// Debug cookie storage:
document.cookie.split(';').forEach(cookie => {
if (cookie.includes('s2_phone')) {
console.log('Found:', cookie);
}
}); -
Browser Privacy Mode
- Incognito/Private mode may block cookies
- Some browsers block third-party cookies by default
- Test in regular browser session
-
Cross-Domain Issues
// Ensure cookie domain matches:
console.log('Cookie domain should be:', window.location.hostname);
Integration Best Practices
PPC Campaign Integration
Google Ads Setup
-
ValueTrack Parameters
Final URL: https://yoursite.com/landing
URL options: {lpurl}?s2number=%2B16125551234&utm_source=google&utm_medium=cpc&utm_campaign={campaignid} -
Campaign-Specific Numbers
Campaign A: ?s2number=%2B16125551111
Campaign B: ?s2number=%2B16125552222
Campaign C: ?s2number=%2B16125553333 -
Dynamic Number Insertion
// Map campaigns to numbers
const campaignNumbers = {
'brand': '+16125551111',
'competitor': '+16125552222',
'generic': '+16125553333'
};
const urlParams = new URLSearchParams(window.location.search);
const campaign = urlParams.get('utm_campaign');
if (campaign && campaignNumbers[campaign]) {
urlParams.set('s2number', campaignNumbers[campaign]);
history.replaceState({}, '', `${window.location.pathname}?${urlParams}`);
}
Facebook Ads Integration
// Facebook Pixel + Phone Tracking
fbq('track', 'PageView');
// After phone number replacement
S2CallTracking('your-uuid-here');
// Track phone number views
setTimeout(() => {
const displayedNumber = document.querySelector('.s2-phone')?.textContent;
if (displayedNumber) {
fbq('trackCustom', 'PhoneNumberViewed', {
number: displayedNumber,
source: 'SendSquared'
});
}
}, 1000);
Google Tag Manager Integration
-
Create Custom HTML Tag
<script>
(function() {
var script1 = document.createElement('script');
script1.src = 'https://app-api.sendsquared.com/tracking/v1/bse-analytics-es3.js';
document.head.appendChild(script1);
var script2 = document.createElement('script');
script2.src = 'https://app-api.sendsquared.com/phone-tracking/v1/phone-tracking.min.js';
document.head.appendChild(script2);
script2.onload = function() {
S2CallTracking('{{SendSquared UUID}}');
// Push event to dataLayer
window.dataLayer.push({
'event': 'phoneTrackingLoaded',
'phoneNumber': new URLSearchParams(window.location.search).get('s2number')
});
};
})();
</script> -
Create Variable for UUID
- Name:
SendSquared UUID
- Type: Constant
- Value: Your UUID
- Name:
-
Set Trigger
- Trigger Type: Page View
- Some Page Views
- Page Path contains
/landing/
WordPress Integration
// Add to functions.php or custom plugin
function add_sendsquared_phone_tracking() {
// Only on specific pages
if (is_page(['contact', 'landing-page', 'services'])) {
?>
<script src="https://app-api.sendsquared.com/tracking/v1/bse-analytics-es3.js"></script>
<script src="https://app-api.sendsquared.com/phone-tracking/v1/phone-tracking.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
S2CallTracking('<?php echo get_option('sendsquared_uuid'); ?>');
});
</script>
<?php
}
}
add_action('wp_footer', 'add_sendsquared_phone_tracking');
// Add settings page for UUID
function sendsquared_settings_page() {
add_options_page(
'SendSquared Settings',
'SendSquared',
'manage_options',
'sendsquared',
'sendsquared_settings_html'
);
}
add_action('admin_menu', 'sendsquared_settings_page');
For Developers
JavaScript API Reference
Core Function
/**
* Initialize SendSquared phone tracking
* @param {string} token - Your SendSquared public token/UUID
* @param {Object} options - Configuration options
* @param {string} options.classRef - CSS class to target (default: null, targets all numbers)
* @param {boolean} options.cookieDomain - Use domain-wide cookie (default: false)
* @param {string} options.pattern - Output format pattern (default: '1.###.###.####')
* @param {boolean} options.clickToCall - Enable click-to-call updates (default: false)
* @param {RegExp} options.sourcePattern - RegEx to match phone numbers (default: /(\b1[-.\s]?)?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\b/g)
*/
S2CallTracking(token, options = {})
Helper Functions
// Get current tracked number
function getTrackedNumber() {
const cookies = document.cookie.split(';');
for (let cookie of cookies) {
if (cookie.trim().startsWith('s2_phone=')) {
return cookie.split('=')[1];
}
}
return null;
}
// Check if tracking is active
function isTrackingActive() {
return document.cookie.includes('s2_phone=');
}
// Clear tracking cookie
function clearTracking() {
document.cookie = 's2_phone=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
}
// Force number update
function updateTrackingNumber(newNumber) {
const encoded = encodeURIComponent(newNumber);
const url = new URL(window.location);
url.searchParams.set('s2number', encoded);
window.location.href = url.toString();
}
Event Listeners
// Listen for tracking completion
window.addEventListener('s2:trackingComplete', function(e) {
console.log('Tracking completed:', e.detail);
// e.detail contains: { originalNumber, newNumber, elementsChanged }
});
// Listen for tracking errors
window.addEventListener('s2:trackingError', function(e) {
console.error('Tracking error:', e.detail);
// e.detail contains: { error, message, uuid }
});
Error Codes Reference
Error Message | Cause | Solution |
---|---|---|
Authentication is required | Missing x-api-key header or no headers at all | Ensure UUID/public token is passed correctly in script initialization |
Origin or referer is required | Missing origin and referer headers | Script must be loaded from a valid domain (not file:// or localhost without proper headers) |
Invalid token or domain | API key not found or domain not whitelisted | 1. Verify UUID/public token is correct. 2. Ensure domain is added to approved domains in SendSquared settings |
S2CallTracking is not defined | Scripts not loaded properly | Check script loading order and network connectivity |
Rate limit exceeded | Too many API calls | Implement caching or contact support for limit increase |
Invalid phone format | Phone number format not recognized | Ensure number includes country code (e.g., +16125551234) |
Cookie storage failed | Browser blocking cookies | Check browser privacy settings and cookie permissions |
Browser Compatibility
Browser | Minimum Version | Notes |
---|---|---|
Chrome | 60+ | Full support |
Firefox | 55+ | Full support |
Safari | 12+ | Full support |
Edge | 79+ | Full support |
IE | 11* | Limited support with ES3 transpilation** |
Note on IE11 Support:
- The tracking script includes a polyfill for
requestIdleCallback
specifically for IE11 and Safari - The script is transpiled to ES3 for broader compatibility
- Features like
WeakSet
andMutationObserver
require IE11 (not available in IE9-10) - For older IE versions, consider implementing a server-side fallback
Performance Considerations
// Optimize for performance
S2CallTracking('your-uuid-here', {
// Limit scope to reduce DOM traversal
classRef: 'phone-tracking-enabled',
// Use efficient RegEx for faster pattern matching
sourcePattern: /\d{10}/g // Simple pattern for 10-digit numbers
});
// Lazy load for below-the-fold content
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
S2CallTracking('your-uuid-here');
observer.disconnect();
}
});
});
observer.observe(document.querySelector('.footer'));
}
Testing Suite Integration
// Jest/Mocha test example
describe('SendSquared Phone Tracking', () => {
beforeEach(() => {
// Mock the S2CallTracking function
window.S2CallTracking = jest.fn().mockResolvedValue(true);
});
test('should initialize with correct UUID', async () => {
await initPhoneTracking();
expect(window.S2CallTracking).toHaveBeenCalledWith('test-uuid-123');
});
test('should replace phone numbers', async () => {
document.body.innerHTML = '<div class="s2-phone">555-1234</div>';
await window.S2CallTracking('test-uuid');
const phone = document.querySelector('.s2-phone');
expect(phone.textContent).toMatch(/\d{3}-\d{4}/);
});
});