Invisible risk scoring
Novera helps your backend decide whether a request is likely human or automated without interrupting legitimate users with a puzzle.
How it works
The browser SDK collects bounded, privacy-conscious summaries and combines them with trusted edge, network, velocity, signed-device, and recent failure context. The browser receives only a random cap_… token. Your backend exchanges it using a secret key; only that authenticated response contains the score.
- Browser calls
POST /api/v1/assessmentswith a public site key. - Borderline live traffic automatically completes a short, single-use managed challenge.
- Novera stores the score and returns an opaque, short-lived token.
- Your frontend sends the token to your own backend with the user's request.
- Your backend calls
POST /api/v1/siteverifywith its secret key and applies policy.
Quick start
1. Execute in the browser
<script src="https://captcha.95-111-249-143.sslip.io/captcha.js" async></script>
<script>
await Captcha.ready();
const token = await Captcha.execute("SITE_PUBLIC_KEY", {
action: "login",
timeout: 15000
});
// Send token with the form. It contains no readable score.
await fetch("/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password, captcha_token: token })
});
</script>2. Verify in your backend
const response = await fetch("https://captcha.95-111-249-143.sslip.io/v1/siteverify", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.NOVERA_SECRET_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
token: req.body.captcha_token,
expected_action: "login",
remote_ip: req.ip
})
});
const result = await response.json();
if (!result.success || result.score < 0.5) {
return res.status(403).json({ error: "Risk verification failed" });
}Browser SDK
The SDK is asynchronous, non-blocking, and safe to load globally. It exposes Captcha.ready(), Captcha.execute(), Captcha.reset(), and Captcha.configure(). A 15-second end-to-end timeout includes any managed challenge and prevents Novera availability from hanging the host application.
Managed escalation
When live traffic is borderline, the SDK transparently solves a bounded SHA-256 proof-of-work challenge and retries. The challenge expires in 45 seconds, accepts exactly one submission, and is bound to the original site key, origin, IP, signed device, and edge fingerprint.
Signals collected
Time before execution; counts of pointer, scroll, touch, focus, visibility, and keyboard-timing events; coarse browser/platform consistency; and software-renderer or automation-artifact booleans. Typed key values, form contents, passwords, DOM snapshots, and session replay are never collected.
NPM
npm install @novera/browser
import { Captcha } from "@novera/browser";
const token = await Captcha.execute(siteKey, { action: "checkout" });Server verification
Send the secret as a Bearer credential. expected_action is strongly recommended and prevents action substitution. Hostname and project binding are checked by Novera automatically.
cURL
curl -X POST https://captcha.95-111-249-143.sslip.io/v1/siteverify \
-H "Authorization: Bearer $NOVERA_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"token":"cap_…","expected_action":"login"}'Python
from novera import Novera
client = Novera(secret_key=os.environ["NOVERA_SECRET_KEY"])
result = client.verify(token, expected_action="login")
if not result.success or result.score < 0.5:
deny_request()PHP
$result = $novera->verify($token, ["expected_action" => "login"]);
if (!$result->success || $result->score < 0.5) {
abort(403);
}Go
result, err := noveraClient.Verify(ctx, token, novera.VerifyOptions{
ExpectedAction: "login",
})
if err != nil || !result.Success || result.Score < 0.5 { deny() }Framework integrations
React / Next.js
Call Captcha.execute immediately before submitting. Send the token to a Route Handler or server action, then call Novera from that server boundary. Do not put NOVERA_SECRET_KEY in a NEXT_PUBLIC_ variable.
Express / Laravel / Django
Verify in middleware close to the protected handler. Check the declared action, then apply a route-specific threshold. For WordPress, verify via a server-side plugin hook before processing login, registration, or form submission.
Risk scores
0.00 means strongly automation-like; 1.00 means strongly human-like. Scores are probabilistic—not proof of identity.
| Range | Level | Managed recommendation |
|---|---|---|
| 0.80–1.00 | Trusted | Allow |
| 0.60–0.79 | Low | Allow / monitor |
| 0.40–0.59 | Medium | Monitor / rate limit |
| 0.20–0.39 | High | Challenge / MFA |
| 0.00–0.19 | Critical | Block |
Actions & policies
Declare semantic actions such as login, signup, checkout, or password_reset. Managed mode recommends allow, monitor, rate_limit, challenge, mfa, or block. Your backend owns enforcement.
Token lifecycle
Tokens contain at least 256 bits of randomness, are stored as SHA-256 hashes, live for no more than 90 seconds in production, and are atomically consumed by successful verification. They are bound to project, site key, hostname, action, and the original browser IP. A token issued to one project cannot be verified with another project's secret.
Testing
Test keys are isolated from live projects and may request deterministic scenarios: always-human, always-bot, expired, and action-mismatch. Never route production traffic through a test project.
await Captcha.execute(TEST_SITE_KEY, {
action: "login",
testScenario: "always-bot"
});Use the protected production login to validate the live integration. Its backend rejects missing, invalid, expired, action-mismatched, and replayed tokens.
Error codes
| Code | Meaning |
|---|---|
| TOKEN_EXPIRED | The short-lived token expired. |
| TOKEN_ALREADY_USED | A replay or duplicate verification was rejected. |
| ACTION_MISMATCH | expected_action does not match the issued token. |
| DOMAIN_NOT_ALLOWED | Origin hostname is not configured. |
| SECRET_KEY_INVALID | The server key is wrong, expired, or revoked. |
| RATE_LIMITED | A project, IP, or key limit was exceeded. |
Security model
Novera assumes an attacker controls the browser, modifies SDK code, uses Burp Suite, automates with Selenium or Playwright, and sends custom HTTP requests. Public site keys are identifiers, not secrets. Secret keys are hashed at rest and never logged in full.
The production edge overwrites forwarding headers and supplies server-observed TLS/HTTP context. Network scoring adds ASN, Tor/hosting classification, IP/subnet/device/connection velocity, signed device continuity, and decaying authentication failures. Direct assessment traffic that bypasses the trusted edge fails closed.
Tenant access is scoped by organization in centralized authorization helpers. Management writes require same-origin checks. Prepared database queries, bounded JSON payloads, exact CORS origin reflection, rate limits, and restrictive response headers provide layered protection.
Privacy
Data minimization is part of the architecture. Novera stores summarized features and high-level explanations, not raw interaction streams. IP addresses are partially masked for display and hashed per project for reputation. Default assessment retention is 30 days and is organization-configurable.
- No keystroke values or typed content.
- No passwords, form fields, or DOM snapshots.
- No session replay.
- No invasive cross-site identity graph.
- Retention cleanup is designed as an idempotent scheduled job.
Failure modes
The browser SDK times out without blocking the host page. Your backend must choose availability behavior. Fail open is reasonable for low-impact actions such as contact forms; sensitive login, account recovery, and payment flows should use a stronger fallback, local rate limiting, or step-up authentication.
Rate limits
Assessment limits combine project, IP, IPv4 /24 or IPv6 /48 subnet, signed-device, and edge-fingerprint windows. Authentication failures decay over one hour, and successful login establishes 90-day device trust. Verification limits apply per secret key. Responses include standard RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset headers; exceeded limits return HTTP 429.
Key rotation
Rotate from Project → Keys. New secrets are displayed once and stored as hashes. During graceful rotation, old and new keys may remain active briefly. Revoke the old key after every backend instance has received the new value. Audit logs record the actor and prefix—never the full secret.
Webhooks
Events include risk.spike, attack.detected, usage.threshold, and secret.rotated. Deliveries use an event ID, timestamped HMAC signature, replay window, and exponential retries. The current console exposes lifecycle scaffolding while outbound delivery remains disabled until an email/webhook provider is configured.
FAQ
Can Novera stop every bot?
No. Bot detection is probabilistic and adversarial. Strong automation can proxy through real browsers, rotate residential IPs, and imitate interaction. Novera combines weak signals and recommends defense-in-depth.
Do shared NAT networks get banned?
No permanent ban is created from IP velocity alone. Network evidence is one probabilistic family combined with browser, behavior, action, and historical context.