URL Shortening & Click Tracking
Shorten URLs in your SMS messages and track click-through analytics.
How It Works
When you enable URL shortening, Exotel replaces long URLs in your SMS body with short links. You can optionally track when recipients click these links.
Parameters
Add these parameters to any Send SMS request:
| Parameter | Required | Type | Description |
|---|---|---|---|
ShortenUrl | Yes | Boolean | true to enable URL shortening |
ShortenUrlParams[Header] | Conditional | String | Required for India. The DLT-registered header that is part of the whitelisted Shortened URL on the DLT platform. Must exactly match the header registered on DLT to avoid message failure |
ShortenUrlParams[CustomDomain] | Optional | String | Custom domain to use for short URLs instead of the default exo.tl. If absent or empty, exo.tl is used. Note: you must route traffic from your custom domain to exo.tl in your DNS settings |
ShortenUrlParams[Tracking] | Optional | Boolean | true to enable click tracking. ShortenUrl must also be true |
ShortenUrlParams[ClickTrackingCallbackUrl] | Optional | String | Webhook URL to receive click events when a recipient clicks the shortened URL |
ShortenUrlParams[TimeToExpiry] | Optional | Integer | Duration in minutes after which the short URL expires. Minimum: 1 minute. Default: 31 days. Maximum: 365 days |
Example Request
- cURL
- Python
- Node.js
- PHP
- Go
curl -u '<api_key>:<api_token>' -X POST https://api.exotel.com/v1/Accounts/<your_sid>/Sms/send \
-d "From=EXOTEL" \
-d "To=+919876543210" \
-d "Body=Check out our sale: https://shop.example.com/sale/winter-2024?utm_source=sms" \
-d "DltEntityId=1234567890" \
-d "ShortenUrl=true" \
-d "ShortenUrlParams[Header]=EXOTEL" \
-d "ShortenUrlParams[Tracking]=true" \
-d "ShortenUrlParams[ClickTrackingCallbackUrl]=https://your-server.com/sms-clicks" \
-d "ShortenUrlParams[TimeToExpiry]=4320"
import requests
data = {
'From': 'EXOTEL',
'To': '+919876543210',
'Body': 'Check out our sale: https://shop.example.com/sale/winter-2024?utm_source=sms',
'DltEntityId': '1234567890',
'ShortenUrl': 'true',
'ShortenUrlParams[Header]': 'EXOTEL',
'ShortenUrlParams[Tracking]': 'true',
'ShortenUrlParams[ClickTrackingCallbackUrl]': 'https://your-server.com/sms-clicks',
'ShortenUrlParams[TimeToExpiry]': '4320',
}
response = requests.post(
'https://api.exotel.com/v1/Accounts/<your_sid>/Sms/send',
auth=('<api_key>', '<api_token>'),
data=data
)
print(response.json())
const apiKey = '<your_api_key>';
const apiToken = '<your_api_token>';
const accountSid = '<your_sid>';
const url = `https://api.exotel.com/v1/Accounts/${accountSid}/Sms/send`;
const params = new URLSearchParams({
From: 'EXOTEL',
To: '+919876543210',
Body: 'Check out our sale: https://shop.example.com/sale/winter-2024?utm_source=sms',
DltEntityId: '1234567890',
ShortenUrl: 'true',
'ShortenUrlParams[Header]': 'EXOTEL',
'ShortenUrlParams[Tracking]': 'true',
'ShortenUrlParams[ClickTrackingCallbackUrl]': 'https://your-server.com/sms-clicks',
'ShortenUrlParams[TimeToExpiry]': '4320',
});
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Basic ' + Buffer.from(`${apiKey}:${apiToken}`).toString('base64'),
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
});
const data = await response.json();
console.log(data);
<?php
$data = array(
'From' => 'EXOTEL',
'To' => '+919876543210',
'Body' => 'Check out our sale: https://shop.example.com/sale/winter-2024?utm_source=sms',
'DltEntityId' => '1234567890',
'ShortenUrl' => 'true',
'ShortenUrlParams[Header]' => 'EXOTEL',
'ShortenUrlParams[Tracking]' => 'true',
'ShortenUrlParams[ClickTrackingCallbackUrl]' => 'https://your-server.com/sms-clicks',
'ShortenUrlParams[TimeToExpiry]' => '4320',
);
$ch = curl_init('https://api.exotel.com/v1/Accounts/<your_sid>/Sms/send');
curl_setopt($ch, CURLOPT_USERPWD, "<api_key>:<api_token>");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
func main() {
endpoint := "https://api.exotel.com/v1/Accounts/<your_sid>/Sms/send"
data := url.Values{}
data.Set("From", "EXOTEL")
data.Set("To", "+919876543210")
data.Set("Body", "Check out our sale: https://shop.example.com/sale/winter-2024?utm_source=sms")
data.Set("DltEntityId", "1234567890")
data.Set("ShortenUrl", "true")
data.Set("ShortenUrlParams[Header]", "EXOTEL")
data.Set("ShortenUrlParams[Tracking]", "true")
data.Set("ShortenUrlParams[ClickTrackingCallbackUrl]", "https://your-server.com/sms-clicks")
data.Set("ShortenUrlParams[TimeToExpiry]", "4320")
req, _ := http.NewRequest("POST", endpoint, strings.NewReader(data.Encode()))
req.SetBasicAuth("<api_key>", "<api_token>")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
}
The long URL in the Body will be replaced with a short link like https://exo.tl/abc123.
Click Tracking Callback
When a recipient clicks the shortened link, Exotel sends a POST request to your ClickTrackingCallbackUrl with the following parameters:
| Field | Description |
|---|---|
sid | Unique ID of the shortened URL |
short_url | The complete shortened URL |
short_code | Key (slug) of the shortened URL |
long_url | The original URL that was shortened |
Tracking | Whether tracking is enabled for this URL |
custom_field | Custom field value passed in the SMS API request |
Expires_at | DateTime (ISO 8601) when the short link expires |
Created_time | DateTime (ISO 8601) when the URL was created |
Last_viewed | DateTime (ISO 8601) when the link was last visited |
Total_clicks | Total number of times the short URL has been clicked |
Account_sid | Exotel Account SID |
Country_code | Country code of the SMS recipient |
Date_created | DateTime (ISO 8601) when the URL was created |
Sms_sid | Unique ID of the SMS message, for cross-referencing |
To | Phone number of the recipient who clicked the link |
city | City where the link was clicked |
Country | Country where the link was clicked |
IP | IP address of the click |
Postal_code | Postal code of the click location |
Region | Region where the link was clicked |
Accuracy_radius | Approximate accuracy radius of the geolocation |
OS_version | OS version of the device that clicked the link |
OS_name | OS name of the device |
Device_name | Device name of the clicker |
Platform_type | Platform type (mobile, desktop, etc.) |
Best Practices
- Set
TimeToExpiryto match your campaign duration — expired links show a generic page - Use click tracking to measure SMS campaign effectiveness
- The DLT-registered header in
ShortenUrlParams[Header]must match your approved sender ID - Short URLs count toward the 2000-character Body limit but are significantly shorter than the original