- SSL Labs analysis takes 60-120 seconds for a full scan
- API was polling up to 6 times with 4-second delays = 24+ seconds
- Vercel Hobby plan has a 10-second timeout
- Result: 504 Gateway Timeout error
- Error response was HTML, not JSON, causing parsing errors
"Unexpected token 'A', 'An error o'..."
This was Vercel's HTML error page starting with "An error occurred..."
The API now uses a cache-first approach:
1. Check SSL Labs Cache (fast, < 1 second)
├─ READY? → Return results immediately ✅
├─ IN_PROGRESS? → Tell user to wait and retry 🔄
└─ NO_CACHE? → Start new scan, tell user to retry ⏱️
2. Never wait/poll (prevents timeout)
3. User retries after 1-2 minutes to get results
{
"status": "READY",
"endpoints": [...],
"host": "example.com",
// ... full SSL Labs data
}{
"status": "PENDING",
"message": "SSL Labs is analyzing this domain. Please try again in a moment.",
"host": "example.com",
"statusDetails": "Analysis in progress"
}{
"status": "PENDING",
"message": "SSL Labs scan initiated. Please try again in 1-2 minutes.",
"host": "example.com",
"hint": "SSL Labs performs a comprehensive analysis which takes time."
}{
"error": "Failed to fetch TLS data",
"message": "Specific error details",
"host": "example.com",
"suggestion": "Try again or check if domain is accessible"
}User runs: /tls example.com
If domain was never scanned or cache is old:
Response: "SSL Labs scan initiated. Please try again in 1-2 minutes."
Action: API triggers background scan (fire-and-forget)
User runs: /tls example.com again
If scan is still running:
Response: "SSL Labs is analyzing this domain. Please try again in a moment."
If scan completed:
Response: Full SSL Labs analysis with grades, vulnerabilities, etc.
SSL Labs caches results for 24 hours, so future requests are instant! ⚡
- Request timeout: 8 seconds (under 10s limit)
- No polling: Prevents cumulative timeout
- AbortController: Properly cancels long requests
- JSON responses: Always returns valid JSON, even for errors
fromCache=on: Check cache firstall=done: Only return completed scansstartNew=on: Trigger new scan (fire-and-forget)
try {
// Try to fetch with timeout
} catch (AbortError) {
// Return timeout message
} catch (Error) {
// Return error message
}# First request (should trigger scan)
curl "http://localhost:5173/api/tls?host=example.com"
# Response: PENDING
# Wait 1-2 minutes, then retry
curl "http://localhost:5173/api/tls?host=example.com"
# Response: Full results# First request
curl "https://your-app.vercel.app/api/tls?host=example.com"
# Check logs
vercel logs --since 10mRequest: /tls google.com
Response: Immediate results ✅
Why: Google is scanned frequently, cache is fresh
Request 1: /tls mydomain.com
Response: "Please try again in 1-2 minutes" 🔄
[Wait 90 seconds]
Request 2: /tls mydomain.com
Response: Full results ✅
Request: /tls invalid.domain.xyz
Response: SSL Labs error (domain doesn't exist) ❌
Request: /tls example.com
Response: "Please try again in a moment" 🔄
Why: SSL Labs API is slow/busy
| Tool | Speed | Depth | Timeout Issues |
|---|---|---|---|
| SSL Labs | Slow (60-120s) | Deep analysis | Fixed with cache-first |
| Qualys SSL Test | Slow (60-90s) | Very deep | Would have same issue |
| SSL Checker | Fast (5-10s) | Basic | Would work |
| testssl.sh | Medium (20-40s) | Deep | Would timeout |
Why we use SSL Labs:
- Industry standard
- Most comprehensive
- Free API
- Trusted by security professionals
- Cache makes it fast for repeated checks
This is normal! SSL Labs needs time to:
- Connect to your server
- Test all SSL/TLS protocols
- Check for vulnerabilities
- Generate comprehensive report
- Cache results
Solution: Wait and retry. Second request will be instant.
Unlikely, but if it happens:
-
Check SSL Labs Status
- Visit: https://www.ssllabs.com/
- See if service is operational
-
Check Domain Accessibility
curl -I https://yourdomain.com
-
Check Vercel Logs
vercel logs --since 10m
-
Use Alternative
- Try: https://www.ssllabs.com/ssltest/
- Manual scan, then cache will be available
Rate limited! SSL Labs limits:
- Max 1 scan per domain per minute
- Max 25 scans per hour from one IP
Solution: Wait 60 seconds and retry.
✅ No More 504 Timeouts - Returns within 8 seconds
✅ Always Valid JSON - No more parsing errors
✅ Better Error Messages - Clear, actionable guidance
✅ Smart Caching - Uses SSL Labs 24-hour cache
✅ Fire-and-Forget Scans - Triggers scan without waiting
✅ User-Friendly Flow - Clear instructions to retry
If you need instant results without waiting:
Run scans manually before users test:
# Pre-scan your domains
curl "https://api.ssllabs.com/api/v3/analyze?host=yourdomain.com&startNew=on"For instant results, consider:
- Mozilla Observatory - Fast, good for headers
- SecurityHeaders.com - Very fast, focused on headers
- SSLMate - Faster but less detailed
- testssl.sh - Command-line tool
- sslyze - Python library
- Requires your own infrastructure
- First Scan - Let users know it takes time
- Show Progress - Display "Analysis in progress" message
- Cache Results - Store in localStorage to avoid re-scanning
- Batch Scans - Scan multiple domains during off-peak hours
- Monitor - Track which domains are scanned most
The TLS API now works reliably within Vercel's timeout limits by:
- Checking cache first (fast)
- Never polling/waiting (prevents timeout)
- Returning helpful PENDING status
- Triggering background scans
- Letting users retry for results
Result: No more 504 errors, always valid JSON responses! 🎉