Web Intent Tracking — Technical Documentation
Last updated: February 2026
Table of Contents
- Overview
- Architecture
- Repository Map
- Core Flows
- Key Services
- Queue Processing
- Entities & Data Models
- API Endpoints
- Session Logic
- Qualification & Automation
- Configuration
- 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
| Repository | Project/Layer | Key Files |
|---|
| sopro-personalisation | JS Widget | sopro-personalisation/wwwroot/js/hq.js |
| sopro-personalisation | Controller | sopro-personalisation/Controllers/HomeController.cs |
| sopro-personalisation | IP Lookup | Services/IPLookupService.cs |
| sopro-personalisation | Widget Data | Data/ClientData/, Data/CompanyData/ |
| sopro-personalisation | Entities | Entities/ |
| anonymous-ip | WebAPI | WebAPI/Controllers/IPLookupController.cs |
| anonymous-ip | Azure Functions | AzureFunctions/Functions/ |
| anonymous-ip | Clearbit Service | Services/ClearbitService.cs |
| anonymous-ip | IP Resolution | Services/MainService.cs |
| anonymous-ip | Company Repo | DataRepository/CompanyRepository.cs |
| anonymous-ip | Entities | Entities/Search.cs, Entities/Company.cs, Entities/Country.cs |
| sopro-sodastream-core | WebIntentAPI | sopro-sodastream-core/WebIntentAPI/Controllers/ |
| sopro-sodastream-core | Queue Consumer | sopro-sodastream-core/SoProQueueConsumer/ |
| sopro-sodastream-core | Dapper Service | sopro-sodastream-core/SharedServices/DapperWebsiteWidgetService.cs |
| sopro-sodastream-core | Daily Automation | sopro-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
| Service | Location | Responsibility |
|---|
IPLookupService | Services/IPLookupService.cs | Calls anonymous-ip API for IP resolution |
SoProPersonalisationDataContext | Data/SoProPersonalisationDataContext.cs | EF Core DbContext for widget data |
IIPAddressData / IPAddressData | Data/IIPAddressData.cs | IP address data access |
anonymous-ip
| Service | Location | Responsibility |
|---|
MainService | Services/MainService.cs | Core IP resolution orchestration |
ClearbitService | Services/ClearbitService.cs | Clearbit Reveal API integration |
CompanyRepository | DataRepository/CompanyRepository.cs | Company data persistence |
SearchRepository | DataRepository/SearchRepository.cs | IP lookup result storage |
DI Registration: Services/Setup/SetupServices.cs and Services/Setup/SetupRepositories.cs
sopro-sodastream-core
| Service | Location | Responsibility |
|---|
DapperWebsiteWidgetService | SharedServices/DapperWebsiteWidgetService.cs | Dapper-based data access for widget visits and sessions |
| WebIntentAPI Controller | WebIntentAPI/Controllers/ | Receives Matomo webhook callbacks |
| Queue Consumer (Intent) | SoProQueueConsumer/IntentTracker/ | Processes intent queue messages |
| WebIntentAutomation | SoProQueueConsumer/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.
{
"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
Search
Location: Entities/Search.cs
| Column | Type | Description |
|---|
Id | int (PK) | Auto-increment |
IpAddress | string | IP address looked up |
CompanyId | int? (FK) | Resolved company |
CountryId | int? (FK) | Country from IP geolocation |
CreatedAt | DateTime | Lookup timestamp |
Source | string | Request source identifier |
Company
Location: Entities/Company.cs
| Column | Type | Description |
|---|
Id | int (PK) | Auto-increment |
CompanyName | string | From Clearbit Reveal |
Domain | string | Company domain |
Industry | string | Industry classification |
EmployeeCount | int? | Estimated employee count |
Country | string | HQ country |
IsDeleted | bool | Soft delete flag |
Country
Location: Entities/Country.cs
| Column | Type | Description |
|---|
Id | int (PK) | Auto-increment |
Name | string | Country name |
IsoCode | string | ISO 3166-1 alpha-2 |
Managed via DapperWebsiteWidgetService using Dapper (not EF Core):
Website Visit Record
| Column | Type | Description |
|---|
Id | bigint (PK) | Auto-increment |
ClientId | int | Client account ID |
WidgetId | string | Widget identifier |
IpAddress | string | Visitor IP |
PageUrl | string | Page visited |
Referrer | string | Referrer URL |
UserAgent | string | Browser info |
CompanyName | string | Resolved company (nullable) |
CompanyDomain | string | Company website (nullable) |
SessionId | int? | Session group assignment |
VisitedAt | DateTime | Visit timestamp |
CreatedAt | DateTime | Record creation |
Website Session
| Column | Type | Description |
|---|
Id | int (PK) | Auto-increment |
ClientId | int | Client account ID |
CompanyName | string | Identified company |
CompanyDomain | string | Company website |
FirstVisitAt | DateTime | Session start |
LastVisitAt | DateTime | Last activity in session |
PageViewCount | int | Number of pages viewed |
IsQualified | bool | Matches campaign criteria |
IsProcessed | bool | Automation has run |
8. API Endpoints
anonymous-ip WebAPI
| Method | Endpoint | Description |
|---|
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)
| Method | Endpoint | Description |
|---|
POST | /api/intent/track | Receive 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
| Rule | Match Type | Description |
|---|
| Industry | Exact match | Company industry ∈ campaign industry list |
| Company Size | Range | Employee count within min-max range |
| Country | Exact match | Company country ∈ campaign country list |
| Revenue | Range | Revenue band within min-max range |
| Exclusion | Negative | Company 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)
| Source | Data | Mechanism |
|---|
| Client Website (hq.js) | Page visit events | HTTP → Matomo → Webhook |
| Clearbit Reveal API | Company identification from IP | HTTP REST |
| Campaign System | Targeting rules for qualification | SQL Server queries |
Downstream (data flows out)
| Target | Data | Mechanism |
|---|
| Campaign Audiences | Auto-sourced prospects | Hangfire daily job |
| Sodastream CRM | Session reports, identified companies | SQL + UI |
| Data Admin | IP Match & Engage configuration | REST API |
Cross-Feature Dependencies
| Feature | Relationship |
|---|
| IP Match & Engage | Web Intent Tracking is the tracking layer; IP Match & Engage adds the campaign engagement automation |
| Audience Management | Auto-sourced prospects are added to campaign audiences |
| Campaign Management | Campaigns define targeting rules used for qualification |
| Search & Filters | Company and prospect data from intent tracking is searchable |
| Email Sending | Auto-sourced prospects eventually receive campaign emails |