Relatude Help

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 bytes

The 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.
  • GetInlineScriptTag saves the request for bot.js, so a page view costs one request: the report. Use GetBotScriptTag when the page's Content-Security-Policy allows no inline script. Both take a nonce.
  • Behind a proxy or a load balancer, call app.UseForwardedHeaders() before UseRelatudeDB(), 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.
  • InfoUrlPath in 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.