EchoScan
UNQ
STB
#···
Cn
En
Jp

EchoScan SDK 接入指南

接入总览

EchoScan 推荐链路:浏览器端运行 Browser Verifier 获取 imprint,随后由你的服务端调用 Lite / Pro 报告接口做业务判定。
浏览器端只负责采集与提交;报告查询和风控策略放在服务端。

Browser Verifier 前端

NPM ESM

npm install @echoscan/browser-verifier
import { createEchoScan } from '@echoscan/browser-verifier'

const { imprint } = await createEchoScan().run()
await fetch('/your-server/imprint', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ imprint })
})

CDN ESM / UMD

<script type="module">
  import { createEchoScan } from 'https://cdn.echoscan.org/v1/echoscan.esm.js'
  const { imprint } = await createEchoScan().run()
  console.log(imprint)
</script>

<script src="https://cdn.echoscan.org/v1/echoscan.umd.js"></script>
<script>
  window.EchoScan.createEchoScan().run().then(({ imprint }) => console.log(imprint))
</script>

Lite 接入

Lite 不需要 API Key,适合公开场景与轻量风险判断。

Node

npm install @echoscan/echoscan
import { createLiteClient } from '@echoscan/echoscan'

const lite = createLiteClient()
const report = await lite.getReport(imprint)

Go

go get github.com/ozzxzzo/fingerprint-system/echoscan/packages/go@latest
package main

import (
	"context"
	"log"

	echoscan "github.com/ozzxzzo/fingerprint-system/echoscan/packages/go"
)

func main() {
	imprint := "fp_session_xxx"

	lite, err := echoscan.NewLiteClient()
	if err != nil {
		log.Fatal(err)
	}

	report, err := lite.GetReport(context.Background(), imprint)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("lyingCount=%v", report["lyingCount"])
}

Python

pip install echoscan
from echoscan import EchoScanLiteClient

imprint = "fp_session_xxx"
lite = EchoScanLiteClient()
report = lite.get_report(imprint)

print(report.get("lyingCount"))

Rust

[dependencies]
echoscan = "0.1.1"
use echoscan::LiteClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let imprint = "fp_session_xxx";
    let lite = LiteClient::new()?;
    let report = lite.get_report(imprint).await?;
    println!("{}", report["lyingCount"]);
    Ok(())
}

Lite 返回值对接

Lite 返回公开场景可直接消费的稳定字段。

{
  "analysis": {
    "browser": {},
    "os": {},
    "hash": {},
    "proxy": {}
  },
  "lyingCount": 0,
  "projection": {
    "audio": { "status": "PASS" },
    "canvas": { "status": "PASS" },
    "font": { "status": "PASS" },
    "ip-geo-timezone": { "status": "PASS" },
    "navigator": { "status": "PASS" },
    "screen": { "status": "PASS" },
    "speech": { "status": "PASS" },
    "webgl": { "status": "PASS" },
    "webrtc": { "status": "PASS" }
  }
}
  • lyingCount:撒谎计数,可直接做风险分层
  • projection.<module>.status:模块结论,枚举 PASS | WARN | FAIL
  • analysis.proxy.status:代理风险状态(PASS/WARN/FAIL)

Pro 接入

Pro 需要服务端 API Key,面向服务端风控与运营分析。

  • 相对 Lite,Pro 增加 projection.bot_detection(是否机器人)和 analysis.proxy.status(代理风险)两类直接可执行信号
  • Pro 返回更完整的模块观测值(如 speechscreenwebgl),适合做规则编排和归因分析
  • Pro 独有历史查询能力:支持 daysfrom/to 时间窗,输出 summary + timeline

Node

npm install @echoscan/echoscan
import { createProClient } from '@echoscan/echoscan'

const pro = createProClient({ apiKey: process.env.ECHOSCAN_PRO_KEY })
const report = await pro.getReport(imprint)
const historyByDays = await pro.getHistory(imprint, { days: 7 })
const historyByRange = await pro.getHistory(imprint, {
  from: '2026-03-01',
  to: '2026-03-18'
})

Go

go get github.com/ozzxzzo/fingerprint-system/echoscan/packages/go@latest
package main

import (
	"context"
	"log"

	echoscan "github.com/ozzxzzo/fingerprint-system/echoscan/packages/go"
)

func main() {
	imprint := "fp_session_xxx"
	days := 7

	pro, err := echoscan.NewProClient("es_xxx_yyy")
	if err != nil {
		log.Fatal(err)
	}

	report, err := pro.GetReport(context.Background(), imprint)
	if err != nil {
		log.Fatal(err)
	}

	history, err := pro.GetHistory(context.Background(), imprint, echoscan.HistoryQuery{
		Days: &days,
	})
	if err != nil {
		log.Fatal(err)
	}

	_, _ = report, history
}

Python

pip install echoscan
from echoscan import EchoScanProClient

imprint = "fp_session_xxx"
pro = EchoScanProClient("es_xxx_yyy")

report = pro.get_report(imprint)
history = pro.get_history(imprint, days=7)

print(report.get("lyingCount"), history.get("summary"))

Rust

[dependencies]
echoscan = "0.1.1"
use echoscan::{HistoryQuery, ProClient};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let imprint = "fp_session_xxx";
    let pro = ProClient::new("es_xxx_yyy")?;

    let report = pro.get_report(imprint).await?;
    let history = pro
        .get_history(imprint, HistoryQuery::Days { days: 7, recent: None })
        .await?;

    println!("{} {}", report["lyingCount"], history["summary"]);
    Ok(())
}
  • daysfrom/to 互斥
  • fromto 必须成对出现
  • 日期格式固定为 YYYY-MM-DD

Pro 返回值对接

Pro 在相同顶层结构下提供更丰富的模块字段,用于服务端策略与运营分析。

{
  "analysis": {
    "browser": {
      "brand": "Google Chrome",
      "browser_version": "146.0.x",
      "browser_version_consistency_status": "PASS",
      "rendering_engine": "Blink"
    },
    "os": {
      "os": "Windows",
      "os_consistency_status": "PASS",
      "version": "11"
    },
    "hash": {
      "accessCount": 31,
      "calculatedAt": "2026-03-19T10:27:25+09:00",
      "stableHash": "....",
      "uniqueHash": "...."
    },
    "proxy": { "status": "PASS" }
  },
  "lyingCount": 0,
  "projection": {
    "bot_detection": {
      "status": "PASS",
      "data": { "is_bot": "No" }
    },
    "screen": {
      "status": "PASS",
      "data": { "resolution": "1920 x 1080" }
    },
    "speech": {
      "status": "PASS",
      "data": {
        "default_voice_lang": "en-US",
        "default_voice_name": "Microsoft David - English (United States)"
      }
    },
    "webgl": {
      "status": "PASS",
      "data": {
        "unmasked_vendor": "Google Inc. (NVIDIA)",
        "unmasked_renderer": "NVIDIA GeForce RTX 3060"
      }
    }
  }
}
  • analysis.hash.accessCount:历史访问次数,可用于熟客识别
  • analysis.browser.*analysis.os.*:环境一致性判断字段
  • projection.bot_detectionanalysis.proxy.status:可直接用于反作弊与代理策略

Pro 历史返回值

{
  "imprint": "fp_session_...",
  "range": {
    "from": "2026-03-01",
    "to": "2026-03-18"
  },
  "recent": 20,
  "summary": {},
  "timeline": []
}
  • summary:聚合统计(适合运营看板)
  • timeline:按时间序列的访问明细
  • daysfrom/to 互斥,日期格式固定 YYYY-MM-DD

错误结构

{
  "code": "auth_failed",
  "httpStatus": 401,
  "message": "Authentication failed",
  "requestId": "req_...",
  "retryable": false
}

建议业务逻辑优先基于 code 判断,message 仅用于展示。

API Key 申请

  • 发送应用信息到 contact@echoscan.org
  • 接入与技术支持:support@echoscan.org
  • 隐私与安全问题:security@echoscan.org
  • 审核通过后发放 Pro key
  • Key 仅保存在服务端环境变量,不放前端