DevRoute SDK
One script tag. Instant device intelligence — eSIM support, fraud signals, network type, and smart conversion routing for every visitor.
DevRoute works entirely client-side. You add a <script> tag,
call DevRoute.init(), and receive a structured result object with
everything you need to route, personalize, or protect your users.
No build step. No dependencies. No npm.
Just a script tag. Works on any website — vanilla HTML, React, Vue, WordPress, Webflow. If it runs JavaScript in a browser, DevRoute works.
Quick Start
Three steps to get your first device result.
Sign up at devroute.app/register. Your key is available immediately on the dashboard.
Paste this in the <head> or just before </body> of your page.
DevRoute.init()
Pass your API key and an onResult callback. That's it.
<!-- Step 2: Add the SDK --> <script src="https://devroute.app/sdk/v3/devroute.min.js"></script> <!-- Step 3: Initialize --> <script> DevRoute.init({ apiKey: 'esim_live_YOUR_API_KEY', onResult: function(result) { console.log('Device:', result.brand, result.model); console.log('eSIM supported:', result.esim.esimSupported); } }); </script>
Installation
CDN (recommended)
Always points to the latest v3 release. Cached globally via Cloudflare CDN.
<script src="https://devroute.app/sdk/v3/devroute.min.js"></script>
Pinned version
Use a specific version if you need reproducible builds.
<script src="https://devroute.app/sdk/v3.0.0/devroute.min.js"></script>
The SDK is a single file with zero dependencies and no external requests
beyond the DevRoute API. It works offline (returns cached data from
sessionStorage on repeat calls within the same browser tab).
DevRoute.init(options)
The single entry point. Call it once per page load — usually right after the script tag.
Results are cached in sessionStorage so repeat calls within the same tab
return instantly without an extra API request.
DevRoute.init({ // Required apiKey: 'esim_live_YOUR_API_KEY', // Called with the result object when detection succeeds onResult: function(result) { // result contains device, eSIM, network, and risk data }, // Called if the API request fails (optional) onError: function(err) { console.warn('DevRoute error:', err.message); } });
Options
| Option | Type | Required | Description |
|---|---|---|---|
apiKey |
string | Required | Your DevRoute API key. Get it from the dashboard. Format: esim_live_... |
onResult |
function | Optional | Callback invoked with the result object on success. Also called immediately with cached data if available. |
onError |
function | Optional | Callback invoked if the API request fails. Receives an Error object. |
apiEndpoint |
string | Optional | Override the API endpoint. Defaults to the DevRoute edge worker. Only change this if instructed by support. |
Response Object
The result object passed to onResult. Available fields depend
on your plan — fields from higher plans are null on lower plans.
{
// ── Device — Free+ ──────────────────────────────────────────────────
id: "sha256_device_hash", // unique device fingerprint
brand: "Samsung",
model: "Galaxy S24",
confidence: 0.92, // 0.0–1.0 detection confidence
detectionMethod: "server-index-lookup",
OS: {
name: "Android",
version: "14"
},
screenResolution: "1080x2340",
pixelRatio: 3,
timezone: "America/New_York",
language: "en-US",
// ── eSIM & Routing — Starter+ ────────────────────────────────────────
family: "Galaxy S24 Series",
GPU: "Adreno 750",
networkType: "4g", // "2g" | "3g" | "4g" | "5g" | "wifi"
device_tier: "premium", // "premium" | "mid" | "budget" | "unknown"
device_hash: "sha256...", // stable fingerprint across sessions
esim: {
esimSupported: true,
dualEsim: false,
conversionStrategy: "guided_install", // see Conversion Strategies below
recommendedFlow: "step_by_step"
},
intelligence: { // see Intelligence Engine section
decisions: {
esim_flow: { value: "step_by_step", reason: "Samsung device on Android 14..." },
friction: { value: "none", reason: "Low risk score, trusted signals" },
security_gate: { value: "none", reason: "No fraud signals detected" },
ui_mode: { value: "streamlined", reason: "Premium device, simplify UI" },
priority: { value: "high", reason: "eSIM capable, premium segment" }
},
narrative: {
headline: "Genuine Samsung user ready for guided eSIM install"
}
},
// ── Network — Growth+ ────────────────────────────────────────────────
IP: "203.0.113.42",
isp: "Comcast Cable",
vpn: false,
ram: 8, // GB, from navigator.deviceMemory
cores: 8, // from navigator.hardwareConcurrency
asn: 7922,
httpProtocol: "HTTP/2",
// ── Fraud + Geo — Enterprise+ ────────────────────────────────────────
emulator: false,
bot: false,
risk_score: 8, // 0–100, higher = riskier
signal_conflicts: [], // array of detected signal contradictions
timezone_mismatch: false, // browser TZ ≠ IP TZ → VPN signal
country: "US", // ISO 3166-1 alpha-2
city: "New York",
region: "New York",
latitude: 40.71,
longitude: -74.00,
postalCode: "10001",
isEUCountry: false,
tlsVersion: "TLSv1.3",
threatScore: 0 // Proxycheck.io threat score (0–100)
}
Field reference
| Field | Type | Description | Plan |
|---|---|---|---|
id | string | SHA-256 device fingerprint (stable across sessions) | Free |
brand | string | Device manufacturer (e.g. "Samsung", "Apple") | Free |
model | string | Device model name | Free |
confidence | number | Detection confidence 0.0–1.0 | Free |
detectionMethod | string | How the device was identified (see Detection Methods below) | Free |
OS.name | string | "iOS" / "Android" / "iPadOS" | Free |
OS.version | string | OS version string e.g. "17.2" or "14" | Free |
screenResolution | string | Physical resolution e.g. "1179x2556" | Free |
pixelRatio | number | Device pixel ratio | Free |
timezone | string | IANA timezone e.g. "America/New_York" | Free |
language | string | Browser language e.g. "en-US" | Free |
family | string | Device family / product line | Starter |
GPU | string | GPU renderer string from WebGL | Starter |
networkType | string | Connection type: "2g" / "3g" / "4g" / "5g" / "wifi" | Starter |
device_tier | string | "premium" / "mid" / "budget" / "unknown" — based on GPU + model | Starter |
device_hash | string | Stable device fingerprint for cross-session tracking | Starter |
esim.esimSupported | boolean | Whether the device supports eSIM | Starter |
esim.dualEsim | boolean | Whether the device supports two concurrent eSIMs | Starter |
esim.conversionStrategy | string | Recommended install strategy — see Conversion Strategies | Starter |
esim.recommendedFlow | string | Recommended UI flow — see Conversion Strategies | Starter |
intelligence.decisions.* | object | Five decisions as { value, reason } — see Intelligence Engine | Starter |
intelligence.narrative.headline | string | One-line summary of the session | Starter |
intelligence.profile | object | User segment, confidence, and signals | Growth |
intelligence.authenticity | object | Authenticity score (0–100) + verdict + signals | Growth |
intelligence.scores | object | risk / conversion / experience scores (0–100 each) | Growth |
IP | string | Client IP address | Growth |
isp | string | Internet service provider name | Growth |
vpn | boolean | True if connection is from a VPN or datacenter | Growth |
ram | number | Device RAM in GB (from navigator.deviceMemory) | Growth |
cores | number | CPU core count (from navigator.hardwareConcurrency) | Growth |
emulator | boolean | True if device is an emulator or automation tool | Enterprise |
bot | boolean | True if headless browser or scraper detected | Enterprise |
risk_score | number | Fraud risk score 0–100 (higher = riskier) | Enterprise |
signal_conflicts | string[] | Detected cross-signal contradictions (empty = clean) | Enterprise |
timezone_mismatch | boolean | Browser timezone differs from IP timezone — VPN signal | Enterprise |
country | string | ISO 3166-1 country code (from Cloudflare edge) | Enterprise |
city | string | City name | Enterprise |
region | string | Region / state name | Enterprise |
latitude / longitude | number | GPS coordinates from Cloudflare edge | Enterprise |
postalCode | string | Postal / ZIP code | Enterprise |
isEUCountry | boolean | True if device is in an EU member country | Enterprise |
tlsVersion | string | TLS version used (e.g. "TLSv1.3") | Enterprise |
threatScore | number | IP threat score from Proxycheck.io (0–100) | Enterprise |
Conversion strategies
The esim.conversionStrategy field tells you how to best route the user. Use it to show the right flow without asking the user to self-identify their device.
| conversionStrategy | recommendedFlow | Meaning | Recommended action |
|---|---|---|---|
"direct_install" | "auto_install" | iOS 16+ or Google Pixel — carrier tap-through available | Show "Activate eSIM" button; deep-link to carrier activation URL |
"guided_install" | "step_by_step" | Samsung or Android 12+ — OS-native eSIM wizard available | Open step-by-step modal linking to Settings > Mobile > Add eSIM |
"qr_install" | "scan_qr" | eSIM supported, no native deep-link flow | Display QR code with scan instructions |
"manual_install" | "manual_setup" | Low confidence detection, cannot verify device | Show activation code entry form as fallback |
"unsupported_device" | "show_unsupported" | Device confirmed as eSIM-incapable | Show upgrade prompt or physical SIM flow |
Detection methods
The detectionMethod field indicates how the device was identified, which reflects detection confidence:
| Value | Confidence | Description |
|---|---|---|
"server-iphone-direct" | High | Matched via screen resolution + DPR matrix (iPhone/iPad) |
"server-multi-signal" | High | Matched via UA + resolution + DPR + OS + touch scoring |
"server-index-lookup" | Medium | Matched via Android model code index (42,000+ codes) |
"server-ua-extract" | Medium | Extracted from UA string with brand inference |
"gpu_cpu_ram_inference" | Low–Medium | Inferred from GPU + CPU family + RAM/screen signals |
Intelligence Engine
Available on Starter and above.
The engine runs five decision layers on every detection and returns structured outputs
with a value and a human-readable reason.
Decisions — intelligence.decisions
Each field returns { value: string, reason: string }. Use value to drive logic and reason to display context or log decisions.
var d = result.intelligence.decisions; // Always use .value to drive your logic console.log(d.esim_flow.value); // "auto_install" console.log(d.esim_flow.reason); // "iOS 17 with confirmed eSIM — use Quick Transfer" console.log(d.friction.value); // "none" | "soft" | "hard" console.log(d.security_gate.value); // "none" | "review" | "block" console.log(d.ui_mode.value); // "streamlined" | "standard" | "cautious" console.log(d.priority.value); // "high" | "medium" | "low"
| Decision | Values | Description |
|---|---|---|
esim_flow | auto_install / step_by_step / scan_qr / manual_setup / show_unsupported | Which eSIM installation flow to trigger |
friction | none / soft / hard | Whether to add verification steps (soft = captcha, hard = SMS OTP) |
security_gate | none / review / block | Whether to allow, flag for review, or block the session |
ui_mode | streamlined / standard / cautious | How much to simplify or guard your UI for this session |
priority | high / medium / low | Conversion priority — use for A/B testing and upsell targeting |
Profile & scores — Growth
Growth plan adds user segment classification and three conversion scores:
var intel = result.intelligence; // User segment intel.profile.segment; // "genuine_user" | "corporate_user" | "privacy_user" // | "traveler" | "developer" | "fraudulent_actor" // | "automated_actor" | "tor_user" | "unclassified" intel.profile.confidence; // 0.0–1.0 segment confidence intel.profile.signals; // ["esim_capable", "residential_isp", ...] // Authenticity intel.authenticity.score; // 0–100 (higher = more authentic) intel.authenticity.verdict; // "authentic" | "suspicious" | "likely_bot" // Scores (0–100) intel.scores.risk; // fraud risk (lower = safer) intel.scores.conversion; // likelihood to convert (higher = better) intel.scores.experience; // UX quality score — use to gate premium features
Error Handling
If the API call fails — network timeout, invalid API key, or plan limit reached —
the onError callback is called. The SDK never throws; all errors
are caught internally.
DevRoute.init({ apiKey: 'esim_live_YOUR_KEY', onResult: function(result) { // happy path }, onError: function(err) { // err.message — human-readable error // Common: "HTTP 401" (bad key), "HTTP 429" (limit reached), network errors console.warn('[DevRoute]', err.message); } });
| HTTP Status | Meaning | What to do |
|---|---|---|
401 | Invalid API key | Check your key in the dashboard. Ensure the request comes from a whitelisted domain. |
429 | Monthly detection limit reached | Upgrade your plan or wait for the next billing cycle. |
500 | Detection failed | Rare. Contact support if it persists. |
Domain locking. API keys can be restricted to specific domains. If you see a 401 on a new domain, add it to the allowed domains list in API Keys settings.
Example — eSIM Routing
Show the right onboarding flow based on real device eSIM support.
DevRoute.init({ apiKey: 'esim_live_YOUR_KEY', onResult: function(result) { var flow = result.esim.conversionStrategy; if (flow === 'direct_install') { // iOS 16+ / Pixel — tap-through carrier activation, no QR needed showActivateButton(carrierDeepLinkUrl); } else if (flow === 'guided_install') { // Samsung / Android 12+ — OS-native Settings wizard showGuidedModal(result.brand, result.OS.version); } else if (flow === 'qr_install') { // eSIM supported, show QR code for profile download showQRCode(); } else if (flow === 'manual_install') { // Low-confidence detection — show activation code entry showActivationCodeForm(); } else if (flow === 'unsupported_device') { // Device can't use eSIM — offer physical SIM or upgrade showPhysicalSimFallback(); } // Optional: use intelligence decisions for UX fine-tuning var d = result.intelligence?.decisions; if (d?.ui_mode?.value === 'streamlined') collapseSecondaryOptions(); if (d?.priority?.value === 'high') showPremiumPlanBanner(); } });
Example — Fraud Detection
Block or flag sessions with high risk signals before checkout. Use intelligence.decisions (Starter+) for decision logic, and risk_score / bot (Enterprise+) for numerical thresholds.
DevRoute.init({ apiKey: 'esim_live_YOUR_KEY', onResult: function(result) { var gate = result.intelligence?.decisions?.security_gate?.value; var friction = result.intelligence?.decisions?.friction?.value; if (gate === 'block') { blockSession(); // high-confidence fraud } else if (gate === 'review' || friction === 'hard') { showSmsVerification(); // suspicious — step-up auth } else if (friction === 'soft') { showCaptcha(); // mild friction only } else { enableCheckout(); // clean session } } });
DevRoute.init({ apiKey: 'esim_live_YOUR_KEY', onResult: function(result) { var riskScore = result.risk_score; // 0–100 var isBot = result.bot; var isVpn = result.vpn; // Growth+ var conflicts = result.signal_conflicts; // array of contradiction strings if (isBot || riskScore > 80) { blockSession(); } else if (isVpn || riskScore > 50 || conflicts.length > 1) { triggerStepUpVerification(); } else { enableCheckout(); } } });
Example — Geo Pricing
Display localized prices based on country without a separate geolocation API call.
var REGIONAL_PRICES = { 'US': { amount: '$4.99', currency: 'USD' }, 'GB': { amount: '£3.99', currency: 'GBP' }, 'DE': { amount: '€4.49', currency: 'EUR' }, 'IN': { amount: '₹99', currency: 'INR' }, }; DevRoute.init({ apiKey: 'esim_live_YOUR_KEY', onResult: function(result) { var country = result.country; var price = REGIONAL_PRICES[country] || REGIONAL_PRICES['US']; document.getElementById('price-display').textContent = price.amount; } });
Plan Limits
| Plan | Monthly detections | Price |
|---|---|---|
| Free | 1,000 | $0 |
| Starter | 25,000 | $39/mo |
| Growth | 100,000 | $129/mo |
| Enterprise | 500,000 | $399/mo |
Limits reset on the 1st of each month. When a limit is reached, the API returns HTTP 429 and detection stops until the next cycle or you upgrade.
Fields by Plan
Fields from higher plans return null on lower plans — no errors, just null values.
| Plan | Available fields |
|---|---|
| Free | id, brand, model, confidence, detectionMethod, OS, screenResolution, pixelRatio, timezone, language |
| Starter | Free + family, GPU, networkType, device_tier, device_hash, esim.*, intelligence.decisions, intelligence.narrative.headline |
| Growth | Starter + IP, isp, vpn, ram, cores, asn, httpProtocol, intelligence.profile, intelligence.authenticity, intelligence.scores |
| Enterprise | Growth + emulator, bot, risk_score, signal_conflicts, timezone_mismatch, country, city, region, latitude, longitude, postalCode, isEUCountry, tlsVersion, threatScore |