This repository contains a fully working implementation that reconstructs Iovation/TransUnion ioBlackBox device fingerprints as generated by snare.js on e-commerce such as Global-E.
The implementation mirrors the snare.js data collection, serialization, and encryption pipeline and produces a valid ioBlackBox fingerprint string that can be used during checkout automation.
Disclaimer This project is for educational and research purposes only. You are responsible for complying with all applicable laws, merchant terms of service, and fraud prevention terms.
Below is a basic example showing how to generate a blackbox fingerprint from a site's snare.js configuration.
func TestGenerateBlackbox(t *testing.T) {
// 1. Find snare.js URL in checkout page HTML
snareURL, err := iovationsnarego.FindSnareURL(checkoutPageHTML)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
// 2. Fetch snare.js and parse build-specific config
config, err := iovationsnarego.ParseSnareJS(snareJSBody)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
// 3. Set BBOUT from the checkout page HTML (not present in snare.js)
// Extract from: var io_bbout_element_id = 'ioBlackBox';
config.BBOUT = "ioBlackBox"
// 4. Create generator
gen, err := iovationsnarego.NewBlackboxGenerator(config, false, false)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
// 5. Generate blackbox
blackbox := gen.Generate(&iovationsnarego.BlackboxParams{
UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
PageURL: "https://webservices.global-e.com/Checkout/v2/8u22/cartId",
Referer: "",
Language: "en-US",
Platform: "Win32",
Resolution: &iovationsnarego.Resolution{Width:2560, Height:1440}, // optional, will use random res if not set
TimezoneOffset: 300,
IntegrationType: iovationsnarego.Form,
})
fmt.Printf("Blackbox: %s\n", blackbox)
// Output: 0400eFj3Hp2K... (400-600 characters)
}ParseSnareJSextracts most build-specific constants directly from the JavaScript source.BBOUTmust be set separately — it lives in the checkout page HTML (var io_bbout_element_id = '...'), not in snare.js. Setconfig.BBOUTafter callingParseSnareJS.- The fingerprint is generated entirely locally with no network requests to Iovation servers.
- If you plan to integrate this into an automation flow, wire up the
Generatefunction as theBlackboxGeneratorFuncin your checkout client.
The returned value is a string in the following format:
"0400" + base64(DES_ECB(serialized_data, key))
Result is typically 400-600 characters and begins with the version prefix 0400.
Each site's snare.js build contains unique hardcoded values that are baked in at build time. These values are extracted dynamically using ParseSnareJS() — no manual configuration is required.
| Value | Description | Extraction Method |
|---|---|---|
IGGY |
64-char hex subscriber/merchant identifier | Direct regex from snare.js |
JSSRC |
CDN/server identifier for the deployment | Base64 decode from snare.js |
BBOUT |
io_bbout_element_id — the HTML element ID where snare.js writes the blackbox |
Extracted from checkout page HTML (var io_bbout_element_id = '...'), not from snare.js |
SVRTIME |
Server-side build timestamp | Direct regex from snare.js |
Token |
Real-time detection token (FLRTD or JSTOKEN) | Direct regex from snare.js |
SUAGT |
Expected User-Agent baked into the build | URL decode from snare.js |
HACCLNG |
Expected Accept-Language baked into the build | URL decode from snare.js |
JSVER |
snare.js SDK version (e.g. "3.1.3") | Direct regex from snare.js |
DES Key |
8-byte DES-ECB encryption key | Hex parse from String.fromCharCode() in snare.js |
Note:
BBOUTis the only config value not extracted byParseSnareJS(). It lives in the checkout page HTML asvar io_bbout_element_id = 'ioBlackBox'and must be set on theSnareConfigby the caller after parsing.
On e-commerce like Global-E, snare.js is loaded on the checkout page via a script tag. Use FindSnareURL() to extract the URL from the page HTML:
snareURL, err := iovationsnarego.FindSnareURL(checkoutPageHTML)
// e.g. "https://s3.global-e.com/snare.js"┌──────────────────┐
│ Checkout Page │
│ (HTML source) │
└────────┬─────────┘
│
├─ 1. FindSnareURL()
│ Extract snare.js script URL
│
├─ 2. Extract BBOUT
│ var io_bbout_element_id = '...'
▼
┌──────────────────┐
│ snare.js │
│ (JavaScript) │
└────────┬─────────┘
│
│ 3. ParseSnareJS()
│ Extract build-specific config
▼
┌──────────────────┐
│ SnareConfig │
│ IGGY, DES Key, │
│ SVRTIME, BBOUT │
└────────┬─────────┘
│
│ 4. NewBlackboxGenerator()
▼
┌──────────────────────────┐
│ BlackboxGenerator │
│ + BlackboxParams │
│ (UA, URL, TZ, etc.) │
└────────┬─────────────────┘
│
│ 5. Generate()
▼
┌──────────────────────────┐
│ Data Collection │
│ ~30 browser/device │
│ properties collected │
└────────┬─────────────────┘
│
│ 6. Serialize
▼
┌──────────────────────────┐
│ Hex-Length-Prefixed │
│ Serialization Format │
│ (max 4000 chars) │
└────────┬─────────────────┘
│
│ 7. Encrypt
▼
┌──────────────────────────┐
│ DES-ECB Encryption │
│ (8-byte key, no IV) │
└────────┬─────────────────┘
│
│ 8. Encode
▼
┌──────────────────────────┐
│ "0400" + base64(...) │
│ ioBlackBox fingerprint │
│ (400-600 chars) │
└──────────────────────────┘
-
Find snare.js
FindSnareURL()extracts the snare.js script URL from the checkout page HTML using regex.
-
Extract BBOUT
- The caller extracts
io_bbout_element_idfrom the checkout page HTML (e.g.var io_bbout_element_id = 'ioBlackBox'). - This is the HTML element ID where snare.js writes the blackbox value.
- Set it on
SnareConfig.BBOUTbefore creating the generator.
- The caller extracts
-
Parse Configuration
ParseSnareJS()extracts all build-specific constants (IGGY, DES key, SVRTIME, etc.) from the JavaScript source using regex patterns.
-
Create Generator
NewBlackboxGenerator()validates the config and initializes the generator with a random seed.
-
Collect Browser Properties
- The generator collects ~30 browser/device properties: User-Agent, browser name/version, OS, platform, screen resolution, timezone, language, page URL, plugins, and more.
- UA parsing matches snare.js internal detection logic (
__if_d(),__if_hn(),__if_jk()).
-
Serialize
- Key-value pairs are serialized in the snare.js hex-length-prefixed format:
hex4(count) + [hex4(keyLen) + UPPER(key) + hex4(valLen) + value]*N - Maximum 4000 characters total.
- Key-value pairs are serialized in the snare.js hex-length-prefixed format:
-
Encrypt
- Single DES in ECB mode (no IV).
- 8-byte key extracted from
String.fromCharCode()in snare.js. - Input padded with null bytes to 8-byte boundary.
-
Encode
- Ciphertext is base64 encoded and prefixed with the version string
"0400".
- Ciphertext is base64 encoded and prefixed with the version string
The IntegrationType field tells the blackbox how the script was integrated on the page:
| Type | Value | Description |
|---|---|---|
Callback |
"callback" |
Page registered window.io_bb_callback to receive the blackbox |
Form |
"form" |
snare.js writes the blackbox into a hidden <input> element |
Function |
"function" |
ioGetBlackbox() was called explicitly to retrieve the blackbox |
For GlobalE checkout flows (e.g. Pokemon Center DE/NZ/AU), the integration type is Form.