Always use short URLs in templates to save characters and reduce SMS segments.
Impact of Long URLs
Long URLs significantly increase message length:
import { getTemplate, renderTemplate } from '@relay-works/templates';
// ❌ Long URL - May require 2 segments
const longResult = renderTemplate(getTemplate('password-reset'), {
company: 'Acme',
url: 'https://mystore.com/account/reset-password?token=abc123&utm_source=sms&utm_medium=text',
minutes: 15
});
console.log(longResult.segments); // 2 segments = $0.04
// ✅ Short URL - Single segment
const shortResult = renderTemplate(getTemplate('password-reset'), {
company: 'Acme',
url: 'https://relay.link/rst-x7k',
minutes: 15
});
console.log(shortResult.segments); // 1 segment = $0.02
URL Shortening Services
Popular Services
Bitly
- Free tier available
- Custom branded domains
- Analytics included
import { BitlyClient } from 'bitly';
const bitly = new BitlyClient(process.env.BITLY_ACCESS_TOKEN!);
async function shortenUrl(longUrl: string): Promise<string> {
const result = await bitly.shorten(longUrl);
return result.link; // https://bit.ly/abc123
}
TinyURL
- Simple and free
- No account required
- Basic functionality
async function shortenWithTinyUrl(longUrl: string): Promise<string> {
const response = await fetch(
`https://tinyurl.com/api-create.php?url=${encodeURIComponent(longUrl)}`
);
return await response.text(); // https://tinyurl.com/abc123
}
Custom Domain (Recommended)
- Best for branding
- Full control
- Professional appearance
// Using a custom short domain like acme.link
const shortUrl = `https://acme.link/${generateShortCode()}`;
URL Validation
Templates enforce a 50-character URL limit:
const validation = validateTemplateData(template, {
company: 'Acme',
url: 'https://very-long-domain-name.com/extremely/long/path/...', // Too long!
minutes: 15
});
if (!validation.valid) {
console.log(validation.errors[0].message);
// "Must be 50 characters or less"
console.log(validation.errors[0].suggestion);
// "Use a URL shortening service"
}
Implementation Example
import { getTemplate, renderTemplate } from '@relay-works/templates';
async function sendPasswordReset(email: string, resetToken: string) {
// Create long URL
const longUrl = `https://myapp.com/reset-password?token=${resetToken}&email=${email}`;
// Shorten it
const shortUrl = await shortenUrl(longUrl);
// Use in template
const result = renderTemplate(getTemplate('password-reset'), {
company: 'Acme',
url: shortUrl,
minutes: 15
});
// Send
await relay.messages.send({
to: getUserPhoneNumber(email),
message: result.text
});
}
URL Shortening Best Practices
-
Always shorten URLs over 30 characters
if (url.length > 30) {
url = await shortenUrl(url);
}
-
Use custom domains for branding
// ✅ Good - branded
url: 'https://acme.link/order-123'
// ❌ Generic
url: 'https://bit.ly/abc123'
-
Remove tracking parameters
// ❌ Don't do this
url: 'https://acme.link/x7k?utm_source=sms&utm_medium=text'
// ✅ Do this - track server-side instead
url: 'https://acme.link/x7k'
-
Test shortened URLs
// Verify shortened URL works
const response = await fetch(shortUrl);
if (!response.ok) {
throw new Error('Shortened URL is invalid');
}
-
Cache shortened URLs
const urlCache = new Map<string, string>();
async function getCachedShortUrl(longUrl: string): Promise<string> {
if (urlCache.has(longUrl)) {
return urlCache.get(longUrl)!;
}
const shortUrl = await shortenUrl(longUrl);
urlCache.set(longUrl, shortUrl);
return shortUrl;
}
Character Savings
Example savings with URL shortening:
| URL Type | Length | Segments | Cost |
|---|
| Long URL (80 chars) | 160+ | 2 | $0.04 |
| Short URL (20 chars) | 100 | 1 | $0.02 |
| Savings | 60 chars | 1 segment | 50% |
Next Steps:
Last modified on