How Custom List Sharing Works
Your custom list is encoded entirely in the URL. No account, no server storage, no cookies. Here's how.
The URL Hash
When you add URLs to your custom list, they're compressed and stored in the URL fragment (the part after #). For example:
https://caniconnect.com/custom#NobwRAZghgNlQEYBsCWB7M...The fragment is never sent to the server. It lives entirely in your browser. When you share the link, the recipient's browser decodes the list locally.
LZ-String Compression
Raw URL lists would create enormous share links. We use LZ-String compression to shrink the data:
Serialize
Your list of URLs is converted to a JSON array.
["https://aws.amazon.com","https://cloud.google.com"]Compress
LZ-String compresses the JSON using a variant of the LZ algorithm optimized for strings. The output is typically 40-60% smaller than the original.
Encode
The compressed output is encoded as a URL-safe string using LZ-String's compressToEncodedURIComponent safe for use in URL fragments without further escaping.
Decoding works in reverse: decompress the hash → parse JSON → render the list. Everything happens in your browser.
Limitations
| Limit | Value | Why |
|---|---|---|
| Max URLs per list | 50 | Keeps the page responsive and avoids overwhelming the browser with concurrent requests. |
| Max URL length | 2,048 chars | Standard URL length limit. Very long URLs inflate the share link disproportionately. |
| Share URL size limit | ~8,000 chars | Browsers and tools (Slack, Discord, Twitter) may truncate URLs longer than this. The progress bar on the custom page tracks your usage. |
| HTTPS/HTTP only | n/a | Browsers can only fetch() HTTP(S) URLs. Other protocols (FTP, SSH, custom ports) are not supported. |
| Server probe rate limit | 10 req/min, 30 URLs/hr | "Check from servers" uses SSRF-protected on-demand probes. Rate limits are per IP to prevent abuse. |
| No persistence | n/a | Lists are not stored on a server. If you lose the URL, the list is gone. Bookmark it! |
Privacy
The URL fragment (#...) is never sent to the server. Per RFC 3986 §3.5, the fragment identifier is resolved client-side only.
This means:
- We never see which URLs are in your list
- No list data appears in server logs or analytics
- If you use "Check from servers", each URL is sent to the API individually, but the full list composition is never transmitted
- If crowdsource is enabled, ping results are submitted per-URL (see Privacy)
Building Links Programmatically
You can generate custom list links from code using the lz-string library (available on npm for JS/TS, or in many languages):
import { compressToEncodedURIComponent } from 'lz-string';
const urls = [
'https://aws.amazon.com',
'https://cloud.google.com',
'https://status.github.com'
];
const hash = compressToEncodedURIComponent(JSON.stringify(urls));
const link = `https://caniconnect.com/custom#${hash}`;
console.log(link);import lzstring, json
urls = [
"https://aws.amazon.com",
"https://cloud.google.com",
"https://status.github.com"
]
lz = lzstring.LZString()
hash = lz.compressToEncodedURIComponent(json.dumps(urls))
print(f"https://caniconnect.com/custom#{hash}")LZ-String has implementations in JavaScript, Python, C#, Java, Go, Ruby, and more. The encoding format is cross-compatible. A link generated in Python works in the browser and vice versa.