35.5 Who is behind a request: IP lookup
db.Services.IPLookup tells code that logs or analyses traffic who is behind a request: where the
address is, whether it belongs to a bot, and what the user agent says it is. It also finds a site's
icon, to show beside a referrer. The hosted service is free, but the license needs the feature
iplookup.
var visitor = await db.Services.IPLookup.LookUpAsync("195.159.120.66", userAgent);
string? country = visitor.Ip?.CountryCode; // "NO"
bool bot = visitor.IsBot;
string? icon = await db.Services.IPLookup.GetFaviconUrlAsync("https://www.example.com/a/page");
// many at once, from a queue of logged requests
var found = await db.Services.IPLookup.LookUpAsync(
queued.Select(r => new IPLookupRequest(r.Ip, r.UserAgent)).ToArray());An IPLookupResult has two parts, each null when nothing was asked or found:
Ip: the country, region, city and position of the address, and whether it is a bot's (IsBot,BotName). An address is a bot's when it is in a network a bot's owner publishes ("google", "bing") or when the bot check found a bot there ("Script"). Missing values are "-". The locations are IP2Location LITE data, and a page that shows them must say "This site or product includes IP2Location LITE data available from https://lite.ip2location.com".UserAgent: the browser, operating system and device type, or the bot it names itself as.
IsBot on the result is true when either part says bot. IsHuman is true when a browser at the
address has passed the bot check and nothing says bot. An address where no browser has run the check
is neither.
The bot check
Bots that run no scripts are known by their address or user agent. Bots that drive a real browser are found by Fingerprint's BotD, which your page runs in the browser:
// in the page's head, or at the end of its body
string tag = db.Services.IPLookup.GetInlineScriptTag();
// <script>(function (root) { … })("/-info/");</script>, about 500 bytesThe browser only talks to your own server. The server serves the scripts and takes the answers under its info path, and passes the answers on to the IP lookup service:
| Route | What it is |
|---|---|
GET /-info/bot.js |
The bot check as a file, for GetBotScriptTag() |
GET /-info/botd.js?v=… |
Fingerprint's BotD (MIT), which the check imports. Browsers cache it for a year |
POST /-info/report?isBot=… |
The browser's answer |
- The answer is for the address, and a bot's answer sticks. Once a browser at an address is found to be a bot, everyone at that address counts as one.
- The tag is the same for every visitor, so pages with it can be output cached.
GetInlineScriptTagsaves the request forbot.js, so a page view costs one request: the report. UseGetBotScriptTagwhen the page's Content-Security-Policy allows no inline script. Both take anonce.- Behind a proxy or a load balancer, call
app.UseForwardedHeaders()beforeUseRelatudeDB(), so the address is the browser's and not the proxy's. - Timing. The report arrives a few hundred milliseconds after the page loads, so look requests up a few seconds after they were served.
- After a start, the server fetches the scripts from the service when a page first asks for them,
and the first pages may go without the check.
GetBotCheckScriptsAsync()fetches them ahead. InfoUrlPathin the server settings (Hosting) moves the routes, and the tags follow it.
IPLookupSettings takes TypeName, ServiceUrl and ApiKey. Lookups are not cached on your
server: they are free, and what browsers report about an address changes.