Skip to main content

Web Intent Tracking — Technical Documentation

Last updated: February 2026


Table of Contents

  1. Overview
  2. Architecture
  3. Repository Map
  4. Core Flows
  5. Key Services
  6. Queue Processing
  7. Entities & Data Models
  8. API Endpoints
  9. Session Logic
  10. Qualification & Automation
  11. Configuration
  12. Integration Points

1. Overview

Web Intent Tracking monitors website visitor activity, resolves IP addresses to companies via Clearbit Reveal (through the anonymous-ip service), groups visits into sessions with 4-hour windows, qualifies companies against campaign targeting rules, and auto-sources prospects via daily Hangfire jobs. The system spans three repos: sopro-personalisation (JS widget + Matomo), anonymous-ip (IP-to-company resolution), and sopro-sodastream-core (queue consumers, session grouping, qualification, daily automation).


2. Architecture


3. Repository Map

RepositoryProject/LayerKey Files
sopro-personalisationJS Widgetsopro-personalisation/wwwroot/js/hq.js
sopro-personalisationControllersopro-personalisation/Controllers/HomeController.cs
sopro-personalisationIP LookupServices/IPLookupService.cs
sopro-personalisationWidget DataData/ClientData/, Data/CompanyData/
sopro-personalisationEntitiesEntities/
anonymous-ipWebAPIWebAPI/Controllers/IPLookupController.cs
anonymous-ipAzure FunctionsAzureFunctions/Functions/
anonymous-ipClearbit ServiceServices/ClearbitService.cs
anonymous-ipIP ResolutionServices/MainService.cs
anonymous-ipCompany RepoDataRepository/CompanyRepository.cs
anonymous-ipEntitiesEntities/Search.cs, Entities/Company.cs, Entities/Country.cs
sopro-sodastream-coreWebIntentAPIsopro-sodastream-core/WebIntentAPI/Controllers/
sopro-sodastream-coreQueue Consumersopro-sodastream-core/SoProQueueConsumer/
sopro-sodastream-coreDapper Servicesopro-sodastream-core/SharedServices/DapperWebsiteWidgetService.cs
sopro-sodastream-coreDaily Automationsopro-sodastream-core/SoProQueueConsumer/WebIntentAutomation/

4. Core Flows

4.1 Page Visit Capture

4.2 IP-to-Company Resolution

4.3 Daily Qualification & Sourcing


5. Key Services

sopro-personalisation

ServiceLocationResponsibility
IPLookupServiceServices/IPLookupService.csCalls anonymous-ip API for IP resolution
SoProPersonalisationDataContextData/SoProPersonalisationDataContext.csEF Core DbContext for widget data
IIPAddressData / IPAddressDataData/IIPAddressData.csIP address data access

anonymous-ip

ServiceLocationResponsibility
MainServiceServices/MainService.csCore IP resolution orchestration
ClearbitServiceServices/ClearbitService.csClearbit Reveal API integration
CompanyRepositoryDataRepository/CompanyRepository.csCompany data persistence
SearchRepositoryDataRepository/SearchRepository.csIP lookup result storage

DI Registration: Services/Setup/SetupServices.cs and Services/Setup/SetupRepositories.cs

sopro-sodastream-core

ServiceLocationResponsibility
DapperWebsiteWidgetServiceSharedServices/DapperWebsiteWidgetService.csDapper-based data access for widget visits and sessions
WebIntentAPI ControllerWebIntentAPI/Controllers/Receives Matomo webhook callbacks
Queue Consumer (Intent)SoProQueueConsumer/IntentTracker/Processes intent queue messages
WebIntentAutomationSoProQueueConsumer/WebIntentAutomation/Daily qualification and sourcing

6. Queue Processing

Queue Architecture

The system uses 7 Azure Queue channels for distributing intent tracking messages:

Why 7 channels? High-volume websites generate thousands of page views per day. Multiple queue channels distribute the processing load across parallel consumers, preventing bottlenecks and ensuring near-real-time processing.

Queue Message Format

{
"ipAddress": "203.0.113.50",
"pageUrl": "https://client.com/pricing",
"referrer": "https://google.com",
"userAgent": "Mozilla/5.0...",
"timestamp": "2026-02-15T10:30:00Z",
"clientId": 42,
"widgetId": "abc123"
}

7. Entities & Data Models

anonymous-ip Entities

Location: Entities/Search.cs

ColumnTypeDescription
Idint (PK)Auto-increment
IpAddressstringIP address looked up
CompanyIdint? (FK)Resolved company
CountryIdint? (FK)Country from IP geolocation
CreatedAtDateTimeLookup timestamp
SourcestringRequest source identifier

Company

Location: Entities/Company.cs

ColumnTypeDescription
Idint (PK)Auto-increment
CompanyNamestringFrom Clearbit Reveal
DomainstringCompany domain
IndustrystringIndustry classification
EmployeeCountint?Estimated employee count
CountrystringHQ country
IsDeletedboolSoft delete flag

Country

Location: Entities/Country.cs

ColumnTypeDescription
Idint (PK)Auto-increment
NamestringCountry name
IsoCodestringISO 3166-1 alpha-2

sopro-sodastream-core (Widget Data)

Managed via DapperWebsiteWidgetService using Dapper (not EF Core):

Website Visit Record

ColumnTypeDescription
Idbigint (PK)Auto-increment
ClientIdintClient account ID
WidgetIdstringWidget identifier
IpAddressstringVisitor IP
PageUrlstringPage visited
ReferrerstringReferrer URL
UserAgentstringBrowser info
CompanyNamestringResolved company (nullable)
CompanyDomainstringCompany website (nullable)
SessionIdint?Session group assignment
VisitedAtDateTimeVisit timestamp
CreatedAtDateTimeRecord creation

Website Session

ColumnTypeDescription
Idint (PK)Auto-increment
ClientIdintClient account ID
CompanyNamestringIdentified company
CompanyDomainstringCompany website
FirstVisitAtDateTimeSession start
LastVisitAtDateTimeLast activity in session
PageViewCountintNumber of pages viewed
IsQualifiedboolMatches campaign criteria
IsProcessedboolAutomation has run

8. API Endpoints

anonymous-ip WebAPI

MethodEndpointDescription
GET/api/iplookup?ip={ip}Resolve IP to company
GET/api/company/{id}Get company details
GET/api/search/{id}Get search/lookup result

WebIntentAPI (sopro-sodastream-core)

MethodEndpointDescription
POST/api/intent/trackReceive page visit from Matomo
GET/api/intent/sessions/{clientId}Get sessions for a client
GET/api/intent/visits/{sessionId}Get visits in a session

9. Session Logic

4-Hour Window Algorithm

For each incoming visit (company + client):
1. Find the most recent session for this company + client
2. If last session's LastVisitAt is within 4 hours of current visit:
a. Add visit to existing session
b. Update session LastVisitAt
c. Increment PageViewCount
3. Else:
a. Create new session
b. Set FirstVisitAt = LastVisitAt = current visit time
c. PageViewCount = 1

Session window: 4 hours (configurable)
Scope: Per company per client — each client×company combination has independent sessions.


10. Qualification & Automation

Daily Hangfire Job

Location: sopro-sodastream-core/SoProQueueConsumer/WebIntentAutomation/
Schedule: Runs daily (typically early morning)

Qualification Logic

For each unprocessed session from the previous day:
1. Load company data (industry, size, location, revenue)
2. For each active campaign with Web Intent enabled:
a. Check company against campaign targeting rules:
- Industry match
- Company size range
- Location/country match
- Revenue range (if specified)
- Not already engaged in this campaign
b. If all criteria match → mark as qualified
3. For qualified companies:
a. Source prospects matching campaign job title targets
b. Add prospects to campaign audience
c. Mark session as processed

Targeting Rule Matching

RuleMatch TypeDescription
IndustryExact matchCompany industry ∈ campaign industry list
Company SizeRangeEmployee count within min-max range
CountryExact matchCompany country ∈ campaign country list
RevenueRangeRevenue band within min-max range
ExclusionNegativeCompany not already in campaign or blocked

11. Configuration

sopro-personalisation

{
"Matomo": {
"TrackerUrl": "https://matomo.example.com",
"SiteId": 1
}
}

anonymous-ip

Location: WebAPI/appsettings.json

{
"ConnectionStrings": {
"AnonymousIPConnection": "Server=...;Database=AnonymousIP;..."
},
"Clearbit": {
"ApiKey": "sk_...",
"BaseUrl": "https://reveal.clearbit.com/v1"
}
}

sopro-sodastream-core

Queue configuration for intent tracking channels in the SoProQueueConsumer configuration:

{
"IntentTracking": {
"QueueChannels": 7,
"QueuePrefix": "intent-queue-",
"SessionWindowHours": 4,
"DailyAutomationEnabled": true
}
}

12. Integration Points

Upstream (data flows in)

SourceDataMechanism
Client Website (hq.js)Page visit eventsHTTP → Matomo → Webhook
Clearbit Reveal APICompany identification from IPHTTP REST
Campaign SystemTargeting rules for qualificationSQL Server queries

Downstream (data flows out)

TargetDataMechanism
Campaign AudiencesAuto-sourced prospectsHangfire daily job
Sodastream CRMSession reports, identified companiesSQL + UI
Data AdminIP Match & Engage configurationREST API

Cross-Feature Dependencies

FeatureRelationship
IP Match & EngageWeb Intent Tracking is the tracking layer; IP Match & Engage adds the campaign engagement automation
Audience ManagementAuto-sourced prospects are added to campaign audiences
Campaign ManagementCampaigns define targeting rules used for qualification
Search & FiltersCompany and prospect data from intent tracking is searchable
Email SendingAuto-sourced prospects eventually receive campaign emails