Debug. raw HttpContext.Items state (TagHelper input)
AggregatedEvidence present: True
BotDetectionResult present: True
evidence.RiskBand = Low
evidence.BotProbability = 1
evidence.Confidence = 0.5
Behaviour-aware Razor
This page is rendered by ASP.NET Core MVC with StyloBot middleware in
process. No gateway, no third-party service, no JavaScript on the
client. Every <sb-*> tag below reads from the same
DetectionDisplayModel the detection pipeline populated
before this view started rendering.
Demo mode. flip the verdict by appending
?demo=<preset> to any URL. Same code path as the
ml-bot-test-mode header; opt-in via
BotDetection:TestModeQueryParam.
1. Your fingerprint card (<bot-detection-details />)
Per-request fingerprint computed by the in-process detection pipeline.
Verdict, bot probability, risk band, recommended action, top reasons,
and the centroid-projection radar. all read from the same
DetectionDisplayModel the detection middleware populated
before this view rendered. The whole upper card links to your
signature's detail page on the embedded dashboard at
/_stylobot.
2. Compact detection card (<sb-summary variant="card" />)
Same detection data, condensed into the inline card the dashboard
uses on dense rows. Drop-in for a sidebar, a row badge, or a wide
inline indicator next to a CTA.
Bot probability
100%
Confidence
50%
Processing
1.2ms
Policy
default
3. Risk-gated content (<sb-risk>)
Welcome back. You scored Low risk. full
access. This block is wrapped in
<sb-risk max="Low"> so it renders only
for visitors the engine classifies as Low or VeryLow.
4. Signal-driven variation (<sb-signal>)
Detected as a declared bot. If you're a verified
crawler, you're allowed; otherwise the route handlers downstream will
reject you.
5. Honeypot form (<sb-honeypot />)
This form contains three offscreen trap fields. Humans don't see them;
bots fill them in. View source to confirm they're there.
6. Inline signal table (<vc:sb-all-signals show-descriptions="false" />)
Condensed inline form of the All signals
page. Renders every key/value pair the detection pipeline wrote to
this request's signal blackboard, grouped by namespace prefix. Same
view component the dedicated /Home/Signals page uses, just with the
longform descriptions collapsed for embedding.
All signals for this request
59 keys
risk: Low (100 %)
attestation.* (3)
| Key |
Value |
Source |
attestation.api_key |
false |
HeaderContributor
|
attestation.fetch_metadata |
false |
HeaderContributor
|
attestation.programmatic |
false |
HeaderContributor
|
behavioral.* (1)
| Key |
Value |
Source |
behavioral.anomaly |
false |
BehavioralContributor
|
h2.* (5)
| Key |
Value |
Source |
h2.behind_proxy |
false |
Http2FingerprintContributor
|
h2.is_http2 |
false |
Http2FingerprintContributor
|
h2.population_http2_rate |
0 |
Http2FingerprintContributor
|
h2.population_samples |
1 |
Http2FingerprintContributor
|
h2.protocol |
HTTP/1.1 |
unknown
|
h3.* (2)
| Key |
Value |
Source |
h3.is_http3 |
false |
Http3FingerprintContributor
|
h3.protocol |
HTTP/1.1 |
Http3FingerprintContributor
|
header.* (11)
| Key |
Value |
Source |
header.count |
10 |
HeaderContributor
|
header.has_accept |
true |
HeaderContributor
|
header.has_accept_encoding |
true |
HeaderContributor
|
header.has_accept_language |
false |
HeaderContributor
|
header.has_proxy_headers |
false |
HeaderContributor
|
header.is_service_worker_fetch |
false |
HeaderContributor
|
header.is_websocket_upgrade |
false |
HeaderContributor
|
header.sec_fetch_dest |
|
HeaderContributor
|
header.sec_fetch_mode |
|
HeaderContributor
|
header.sec_fetch_same_origin |
false |
HeaderContributor
|
header.sec_fetch_site |
|
HeaderContributor
|
header_correlation.* (2)
| Key |
Value |
Source |
header_correlation.distinct_signatures |
4 |
HeaderCorrelation
|
header_correlation.header_fingerprint |
FC532CE0 |
HeaderCorrelation
|
heuristic.* (3)
| Key |
Value |
Source |
heuristic.confidence |
0.57502633250087 |
HeuristicContributor
|
heuristic.early_completed |
true |
HeuristicContributor
|
heuristic.prediction |
bot |
HeuristicContributor
|
ip.* (4)
| Key |
Value |
Source |
ip.address |
10.10.10.1 |
IpContributor
|
ip.is_datacenter |
false |
IpContributor
|
ip.is_ipv6 |
false |
IpContributor
|
ip.is_local |
true |
IpContributor
|
proxy.* (1)
| Key |
Value |
Source |
proxy.topology |
Direct |
IpContributor
|
risk.* (2)
| Key |
Value |
Source |
risk.friendly_pin_trace |
fired:bot_type=Internal (network-trusted) |
unknown
|
risk.justification |
Trusted internal client (network position verified) |
unknown
|
session.* (1)
| Key |
Value |
Source |
session.current_state |
PageView |
unknown
|
signature.* (3)
| Key |
Value |
Source |
signature.header_hashes |
{"accept":"AUX_tJpM41ouddM0xxrYJQ","accept-encoding":"IcvRpgU6pLuve_BlYZaAmA","_header_order":"SXhf0tTtTIzy__dkUXn27A"} |
unknown
|
signature.multifactor |
MultiFactorSignatures(3 factors, primary=uWNcSFefwGoR...) |
unknown
|
signature.primary |
uWNcSFefwGoRhoNlt9PuWA |
BehavioralWaveformContributor
|
tcp.* (1)
| Key |
Value |
Source |
tcp.connection_header |
|
TcpIpFingerprintContributor
|
time.* (4)
| Key |
Value |
Source |
time.day_of_week |
tue |
unknown
|
time.hour_of_day |
13 |
unknown
|
time.is_business_hours |
true |
unknown
|
time.is_weekend |
false |
unknown
|
tls.* (2)
| Key |
Value |
Source |
tls.available |
true |
TlsFingerprintContributor
|
tls.is_https |
true |
TlsFingerprintContributor
|
transport.* (7)
| Key |
Value |
Source |
transport.headers_trusted |
true |
unknown
|
transport.is_signalr |
false |
unknown
|
transport.is_streaming |
false |
unknown
|
transport.protocol |
http |
TransportProtocolContributor
|
transport.protocol_class |
unknown |
unknown
|
transport.transport_class |
http |
unknown
|
transport.trust_reason |
PrivatePeer |
unknown
|
ua.* (7)
| Key |
Value |
Source |
ua.bot_instance |
scrapy.org |
UserAgentContributor
|
ua.bot_name |
Scrapy scrapy.org |
UserAgentContributor
|
ua.bot_type |
Scraper |
UserAgentContributor
|
ua.family |
Scrapy scrapy.org |
UserAgentContributor
|
ua.family_version |
2.5.0 |
UserAgentContributor
|
ua.is_bot |
true |
UserAgentContributor
|
ua.raw |
Scrapy/2.5.0 (+https://scrapy.org) |
UserAgentContributor
|
7. Endpoint traffic shaping
The opening Razor view from the talk also wires up three minimal-API
endpoints at the routing layer:
GET /api/data. .BlockBots():
all bots refused. Try it.
GET /sitemap.xml.
.BlockBots(allowVerifiedBots: true, allowSearchEngines: true).
Try it.
POST /api/login.
.BotPolicy("strict", blockThreshold: 0.5).
Tip: hit /api/data while demo mode is set to
scrapy or curl and watch it 403.