Calltouch Analytics Integration
Calltouch is call tracking with an analytics core: dynamic number replacement, call and lead attribution, dashboards by source. Integration covers tracker installation, event setup, lead data submission via API, and proper functioning in SPA environments.
Tracker Architecture
Calltouch works through the JS library ct.js, which:
- Sets cookies
_ct_sessionand_ct_leadwith visit identifiers - Replaces phone numbers on the page via CSS classes or
data-ct-phoneattributes - Sends interaction events to Calltouch servers
<!-- Tracker installed in <head> as high as possible -->
<script>
(function(w, n) {
w[n] = w[n] || [];
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = '//mod.calltouch.ru/init.js?id=SITE_ID';
var f = document.getElementsByTagName('script')[0];
f.parentNode.insertBefore(s, f);
})(window, 'ct');
</script>
SITE_ID is the identifier from "Settings → Integrations" in your account.
Getting session_id for Lead Submission
Before sending a lead to the backend, get the current session_id. Calltouch provides a synchronous method:
// Get session ID
function getCalltouchSessionId() {
if (typeof ct === 'undefined') return null;
try {
// Returns { sessionId: '...', ... }
const data = ct('getSessionId');
return data?.sessionId ?? null;
} catch (e) {
console.warn('Calltouch: failed to get session ID', e);
return null;
}
}
// Use on form submit
document.getElementById('lead-form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
formData.append('ct_session_id', getCalltouchSessionId() ?? '');
await fetch('/api/leads', { method: 'POST', body: formData });
});
Submitting Leads via Calltouch API
After saving a lead on the backend, send it to Calltouch so the system can attribute it to the source.
Endpoint: POST https://api.calltouch.ru/calls-service/RestAPI/requests/[siteId]/register/
curl -X POST \
'https://api.calltouch.ru/calls-service/RestAPI/requests/12345/register/' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'sessionId=SESSION_ID_FROM_COOKIE&subject=Lead from website&name=John Smith&phoneNumber=79001234567&[email protected]&requestUrl=https://example.com/contact&sessionToken=YOUR_TOKEN'
Parameters:
-
sessionId— fromct('getSessionId') -
sessionToken— site token from account (API section) -
subject— lead subject (free text) -
phoneNumber— phone without+and spaces -
requestUrl— URL of the page the lead came from
PHP Implementation
// app/Services/CalltouchService.php
class CalltouchService
{
private string $siteId;
private string $sessionToken;
private string $apiBase = 'https://api.calltouch.ru/calls-service/RestAPI/requests';
public function __construct()
{
$this->siteId = config('services.calltouch.site_id');
$this->sessionToken = config('services.calltouch.token');
}
public function registerRequest(array $data, string $sessionId): array
{
$url = "{$this->apiBase}/{$this->siteId}/register/";
$response = Http::asForm()->timeout(5)->post($url, [
'sessionId' => $sessionId,
'sessionToken' => $this->sessionToken,
'subject' => $data['subject'] ?? 'Lead from website',
'name' => $data['name'] ?? '',
'phoneNumber' => preg_replace('/\D/', '', $data['phone'] ?? ''),
'email' => $data['email'] ?? '',
'requestUrl' => $data['url'] ?? '',
'comment' => $data['comment'] ?? '',
]);
if (!$response->ok()) {
Log::error('Calltouch API error', [
'status' => $response->status(),
'body' => $response->body(),
'session' => $sessionId,
]);
}
return $response->json() ?? [];
}
}
SPA: Correct Number Replacement
In React/Vue/Angular apps, ct.js performs replacement once after load. On navigation without full reload, numbers stop being replaced. Fix by calling ct('reInit') on route change:
// React Router v6
import { useLocation } from 'react-router-dom';
import { useEffect } from 'react';
export function CalltouchReinit() {
const location = useLocation();
useEffect(() => {
if (typeof window.ct === 'function') {
// Small delay — let component render new numbers
setTimeout(() => window.ct('reInit'), 300);
}
}, [location.pathname]);
return null;
}
For Vue Router:
router.afterEach(() => {
setTimeout(() => window.ct?.('reInit'), 300);
});
Setting Up Goals via Calltouch Events API
Beyond calls and leads, send arbitrary conversion events:
// Event "add to cart"
ct('send', 'event', {
eventName: 'add_to_cart',
value: 2990,
currency: 'RUB',
orderId: 'CART-456',
});
// Event "purchase"
ct('send', 'event', {
eventName: 'purchase',
value: 14500,
currency: 'RUB',
orderId: 'ORDER-789',
items: [
{ id: 'SKU-001', name: 'Product A', quantity: 2, price: 7250 }
],
});
Webhook for Incoming Calls
Calltouch can send a POST request to your server on each call — useful for auto-creating deals in CRM.
Example payload:
{
"callId": "CT-12345",
"sessionId": "abc...xyz",
"phoneNumber": "+79001234567",
"duration": 124,
"status": "answered",
"source": "google/cpc",
"medium": "cpc",
"campaign": "brand-search",
"keyword": "our brand"
}
Webhook endpoint is registered in account → "Integrations → Webhook".
Debugging
Verification checklist:
- DevTools → Network: check that
init.js?id=SITE_IDloads without errors (200) - Console:
ct('getSessionId')should return an object with non-emptysessionId - Number replacement: page should show Calltouch pool number, not original
- Account → "Lead Log": verify test lead appears with correct source
Timeline
Installing tracker and setting up number replacement — 3–4 hours. Backend API implementation for lead submission — 4–6 hours. Webhook setup and CRM integration — separate task, 1–2 days depending on CRM.







