-
Notifications
You must be signed in to change notification settings - Fork 8
Description
Summary
Trusted Server already has a first-party proxy integration for DataDome (client-side SDK + signal collection proxied through the publisher's domain). The official DataDome Fastly Compute module adds a second layer: server-side request validation that calls DataDome's Protection API on every incoming request to block/challenge bots before they reach the origin.
This proposal is to implement that server-side validation layer in Rust, making it edge-provider agnostic — not tied to Fastly's JS SDK or any other platform-specific runtime.
Background
Two Layers of DataDome Integration
| Layer | Status | What It Does |
|---|---|---|
| 1. First-party proxy | Built (currently disabled) | Proxies tags.js + signal collection through publisher domain. Rewrites HTML/DOM references to use first-party paths. |
| 2. Server-side validation | Not built | On every request, calls DataDome's Protection API with request metadata. Blocks/challenges bots before they reach the origin. |
Layer 1 makes client-side signals more reliable (bypasses ad blockers that block datadome.co). Layer 2 blocks bots even without client-side signals. Together they provide full coverage.
What the Official Fastly Compute Module Does
The @datadome/module-fastly-compute npm package:
- Intercepts every incoming request before it reaches the origin
- Sends request metadata to
POST https://api.datadome.co/validate-request/(the Protection API) - Blocks or challenges bots (returns 403, CAPTCHA pages, etc.)
- Only forwards allowed requests to the origin, enriched with DataDome metadata headers
- Fails open on timeout (allows the request through)
Proposal
New IntegrationRequestFilter Trait
The integration registry currently has no pre-request filtering hook. A new trait would be added:
#[async_trait(?Send)]
pub trait IntegrationRequestFilter: Send + Sync {
fn integration_id(&self) -> &'static str;
/// Return Some(Response) to block/challenge, None to allow.
async fn filter_request(
&self,
settings: &Settings,
req: &Request,
) -> Option<Result<Response, Report<TrustedServerError>>>;
}This is a natural extension of the existing registry pattern (IntegrationProxy, IntegrationAttributeRewriter, IntegrationScriptRewriter, etc.) — it's the one missing lifecycle hook.
Hook Point
Insert after enforce_basic_auth() in route_request(), before any route matching:
for filter in integration_registry.request_filters() {
if let Some(response) = filter.filter_request(settings, &req).await {
return response;
}
}Request Flow
Client Request
→ enforce_basic_auth()
→ IntegrationRequestFilter (NEW — DataDome Protection API call)
→ Bot? → Return block/challenge response
→ Allowed? → Continue
→ Timeout? → Fail open, continue
→ Route matching (integration proxies, publisher origin, etc.)
→ Response
DataDome Implementation
The DataDome IntegrationRequestFilter would:
- Check if the URL matches the exclusion pattern (skip static assets like
.css,.js,.png, etc.) - Extract request metadata (IP via
Fastly-Client-IP/X-Forwarded-For, User-Agent, Referer, URL, method, cookies, headers) POSTto DataDome's Protection API with the server-side key- If DataDome says block → return the block/challenge response directly
- If DataDome says allow → return
None, continue normal processing - On timeout → fail open (allow the request)
Configuration
[integrations.datadome]
enabled = true
# Existing first-party proxy settings (unchanged)
sdk_origin = "https://js.datadome.co"
api_origin = "https://api-js.datadome.co"
cache_ttl_seconds = 3600
rewrite_sdk = true
# New server-side validation settings
server_side_key = ""
client_side_key = ""
protection_api = "https://api.datadome.co"
enable_protection = false # Independent toggle for Layer 2
url_pattern_exclusion = "\\.(css|js|ico|jpg|png|gif|svg|woff2?)$"
timeout_ms = 1500Why This Makes Sense
- Edge-agnostic — The Protection API is plain HTTP. Rust/WASM can call it from Fastly, Cloudflare, or any edge platform. Official DataDome modules are platform-specific. This would be the first Rust implementation.
- Complements existing integration — Layer 1 (proxy) + Layer 2 (validation) together provide full bot protection coverage.
- Ad protection — DataDome has an "Ad Protect" product for invalid traffic (IVT). Server-side validation could filter bots before auction/bidding runs, saving bid costs.
- Clean architecture —
IntegrationRequestFilteris a natural addition to the registry trait system and could be used by other integrations in the future.
Tradeoffs to Consider
| Concern | Detail |
|---|---|
| Latency | Extra roundtrip to DataDome API per request (~1-5ms from edge POPs). URL exclusion pattern mitigates this for static assets. |
| Cost | DataDome bills per validated request. Exclusion patterns for static/internal routes are important. |
| Fail-open | On timeout/error, requests are allowed through (standard across all DataDome modules). |
Files Involved
crates/common/src/integrations/datadome.rs— Extend withIntegrationRequestFilterimplcrates/common/src/integrations/registry.rs— AddIntegrationRequestFiltertrait + registry supportcrates/fastly/src/main.rs— Add filter hook inroute_request()trusted-server.toml— Add new config fields