Quick Start

Get Klixsor running on your server in under 5 minutes.

1

Get a VPS

Provision a fresh Ubuntu 22.04 or Debian 12 server from any provider (Contabo, Hetzner, DigitalOcean, Vultr, OVH, etc). See server requirements below.

2

Run the installer

SSH into your server as root and run:

bash
curl -sSL https://klixsor.com/install.sh | bash -s -- YOUR-LICENSE-KEY

Replace YOUR-LICENSE-KEY with the license key from your purchase email. The installer handles everything — Docker, databases, binaries, firewall, and bot IP list seeding.

3

Save your credentials

When the installer finishes, it prints your admin login, password, and server URL. It also saves them to /opt/klixsor/credentials.txt.

Important: Save your admin password immediately. It's randomly generated and shown only once.
4

Log in and configure

Open http://YOUR-SERVER-IP:8081 in your browser. Log in with the admin credentials. Add your tracking domain, create your first campaign, and you're live.


Server Requirements

Component Minimum Recommended
OS Ubuntu 20.04 / Debian 11 Ubuntu 22.04 / Debian 12
CPU 2 vCPU 4+ vCPU
RAM 4 GB 8+ GB
Storage 40 GB SSD 80+ GB NVMe SSD
Bandwidth 1 TB/month Unlimited / 5+ TB
Provider recommendations: Contabo and Hetzner offer excellent value. For higher traffic, OVH and DigitalOcean provide reliable performance. Any provider with a standard Linux VPS works.

Ports Used

Port Service Access
22SSHPublic (your IP only recommended)
80HTTPPublic
443HTTPSPublic
8081Admin APILocalhost only (behind Nginx)
8090Click EngineLocalhost only (behind Nginx)
5432PostgreSQLLocalhost only
9000Analytics EngineLocalhost only
6379RedisLocalhost only

Installation

What the installer does

  1. Installs system dependencies (curl, Docker, fail2ban, UFW)
  2. Sets up Docker containers for PostgreSQL 16, analytics engine, and Redis 7
  3. Downloads Klixsor API and Click Engine binaries
  4. Runs database migrations
  5. Creates an admin user with a random password
  6. Configures systemd services for auto-start on boot
  7. Sets up UFW firewall (ports 22, 80, 443 only)
  8. Seeds 17 bot IP lists and triggers initial sync

Installation command

bash
curl -sSL https://klixsor.com/install.sh | bash -s -- YOUR-LICENSE-KEY

Custom version

To install a specific version instead of the latest:

bash
curl -sSL https://klixsor.com/install.sh | bash -s -- --version 1.2.0 YOUR-LICENSE-KEY

File locations

PathContents
/opt/klixsor/Binaries, config, license key, docker-compose
/opt/klixsor/configs/config.yamlMain configuration file
/opt/klixsor/.envDatabase passwords, JWT secret, license key
/opt/klixsor/credentials.txtGenerated credentials (readable by root only)
/opt/klixsor/license.keyYour license key
/var/lib/klixsor/Database data (PostgreSQL, analytics engine, Redis)
/var/lib/klixsor/backups/Automatic pre-update backups

First Steps After Install

  1. Log in — Open http://YOUR-SERVER-IP/api/v1/auth/login with the credentials from the installer output
  2. Add a tracking domain — Go to Domains → Add Domain. Point your domain's DNS A record to your server IP first.
  3. Set up SSL — Click the shield icon (Setup SSL) on your domain row. This auto-provisions a Let's Encrypt certificate — no manual certbot commands needed.
  4. Create a traffic source — Define where your traffic comes from. Choose from 33 built-in templates covering all major ad platforms (Facebook, Google, TikTok, Microsoft, Snapchat, Pinterest, Twitter/X, LinkedIn, Reddit, Taboola, Outbrain, and 20+ push/native/adult networks) with pre-configured URL parameters
  5. Add offers — Add the affiliate offers you want to route traffic to
  6. Create a campaign — Set up your first campaign with flows, landing pages, and offers
  7. Verify bot detection — Check Bot Management → IP Lists to confirm all lists are synced
  8. Configure GeoIP — Go to Settings → GeoIP Databases and enter your MaxMind Account ID and License Key, then download the databases. See GeoIP Databases for full setup instructions. This is required for country/city tracking.
  9. Check Settings — Go to Settings in the sidebar to verify your license status, version, and usage limits
Klixsor Dashboard
The Klixsor dashboard showing today's clicks, bot detection, revenue, and 7-day trend

Adding Domains

Adding a tracking domain to Klixsor is a 3-step process: configure DNS, add the domain in the admin panel, then provision SSL.

Step 1: Configure DNS

In your domain registrar (Namecheap, Cloudflare, GoDaddy, etc.), create a DNS record pointing to your Klixsor server.

For subdomains (recommended — e.g., track.yourdomain.com):

DNS
Type: A (or CNAME)
Name: track
Value: YOUR-SERVER-IP
TTL: 300 (or Auto)

For root domains (e.g., yourdomain.com):

DNS
Type: A
Name: @
Value: YOUR-SERVER-IP
TTL: 300 (or Auto)

Your server's IP is shown in the admin panel — the Domains page displays DNS setup instructions with the correct IP pre-filled.

Step 2: Add the domain in Klixsor

  1. Go to Domains → Add Domain
  2. Enter the full domain name (e.g., track.yourdomain.com)
  3. Optionally set an Index Campaign to handle visitors to the domain root
  4. Save the domain
Domains page
Domains page showing SSL status, health monitoring, and domain settings

Step 3: Setup SSL

Click the shield icon (Setup SSL) on the domain row. Klixsor will automatically:

  • Verify DNS is pointing to your server
  • Create an Nginx server block for the domain
  • Provision a free Let's Encrypt SSL certificate
  • Configure HTTPS with automatic HTTP → HTTPS redirect

The entire process takes about 10 seconds. Once complete, the SSL column will show Enabled.

Tip: DNS propagation can take 5 minutes to 24 hours. If SSL setup fails with a DNS error, wait a bit and try again.
Cloudflare users: Set your domain's proxy status to DNS only (grey cloud) when setting up SSL. You can enable the Cloudflare proxy after the certificate is issued.

SSL / HTTPS Setup

SSL is critical for tracking domains. Without HTTPS, browsers will show security warnings and may block redirects and tracking pixels.

Automatic SSL (recommended)

Klixsor handles SSL automatically. When you click the Setup SSL button on a domain, it:

  1. Creates an Nginx server block for the domain
  2. Obtains a free Let's Encrypt certificate via certbot
  3. Configures HTTPS with automatic HTTP → HTTPS redirect
  4. Sets up automatic certificate renewal (via systemd timer)

No manual configuration required. The installer pre-installs Nginx and Certbot for you.

Manual SSL (advanced)

If you prefer manual control, you can provision certificates yourself:

bash
# Get a certificate manually
certbot certonly --nginx -d track.yourdomain.com

# Or use standalone mode (stops nginx temporarily)
certbot certonly --standalone -d track.yourdomain.com

# Certificates renew automatically via systemd timer
systemctl list-timers | grep certbot

Cloudflare (if using Cloudflare DNS)

Set Cloudflare SSL mode to Full (Strict) and use Cloudflare's origin certificate.

Note: If using Cloudflare proxy (orange cloud), set the SSL mode to "Full" and disable caching for tracking paths to avoid redirect interference. Set proxy to DNS only (grey cloud) when first provisioning the certificate.

Nginx Reverse Proxy

Nginx is installed and configured automatically by the Klixsor installer. It proxies HTTPS traffic to the Klixsor services running on localhost.

How it works

The installer creates a base Nginx config at /etc/nginx/sites-available/klixsor-admin that:

  • Proxies /api/ requests to the Admin API (:8081)
  • Proxies all other requests to the Click Engine (:8090)

When you click Setup SSL on a domain, Klixsor creates a dedicated Nginx config at /etc/nginx/sites-available/klixsor-trk-{domain} with SSL termination.

Config files

bash
# Base config (created by installer)
/etc/nginx/sites-available/klixsor-admin

# Per-domain configs (created by Setup SSL)
/etc/nginx/sites-available/klixsor-trk-track.yourdomain.com

# Check all configs
nginx -t

# Reload after manual changes
systemctl reload nginx

Custom Nginx config (advanced)

If you need to customize the Nginx config for a domain (e.g., add custom headers, rate limiting), edit the per-domain config file directly:

bash
# Edit the tracking domain config
nano /etc/nginx/sites-available/klixsor-trk-track.yourdomain.com

# Test and reload
nginx -t && systemctl reload nginx
Note: Re-running Setup SSL on a domain will overwrite custom changes. Make backups before re-provisioning.

GeoIP Databases

Configure MaxMind GeoLite2 databases for accurate country, city, and ISP detection on every click.

Why MaxMind credentials are needed

MaxMind now requires users to create a free account and use their own credentials to download GeoLite2 databases. This is a licensing change from MaxMind — the databases are still free, but you need an account to access them. Without GeoIP databases, Klixsor cannot determine visitor location, ISP, or connection type.

Step 1: Create a free MaxMind account

  1. Go to maxmind.com/en/geolite2/signup
  2. Fill out the registration form (name, email, company optional)
  3. Verify your email and set a password
  4. Log into your MaxMind account dashboard

Step 2: Generate a license key

  1. In your MaxMind account, go to Manage License Keys (under Services)
  2. Click Generate New License Key
  3. Give it a description (e.g., "Klixsor") and confirm
  4. Copy the Account ID and License Key — the license key is shown only once

Step 3: Configure in Klixsor

  1. Go to Settings → GeoIP Databases
  2. Click Configure MaxMind
  3. Enter your MaxMind Account ID and License Key
  4. Click Save
  5. Click Download Databases to fetch GeoLite2-City and GeoLite2-ASN

The download typically takes 10-30 seconds depending on your server's internet speed. Both databases are required for full geolocation and ISP detection.

Notification banner

If GeoIP databases are not configured, Klixsor displays a notification banner at the top of the dashboard after login. This banner appears on every page until you configure and download the databases. Once configured, the banner disappears automatically.

Important: GeoIP databases should be updated periodically (MaxMind updates them weekly). Use the Update Now button in Settings → GeoIP Databases to re-download the latest versions.

Databases used

DatabasePurposeData provided
GeoLite2-CityLocation detectionCountry, region/state, city, latitude/longitude, timezone
GeoLite2-ASNNetwork detectionISP name, ASN number, organization, connection type

Configuration File

The main configuration is at /opt/klixsor/configs/config.yaml. Here are the key sections:

config.yaml
server:
  api_port: 8081          # Admin API port
  click_port: 8090        # Click engine port
  server_ip: ""           # Auto-detected if empty

postgres:
  host: localhost
  port: 5432
  user: klixsor
  password: "your-password"
  database: klixsor
  max_conns: 20           # Connection pool size

clickhouse:
  host: localhost
  port: 9000
  database: klixsor

redis:
  addr: localhost:6379
  password: "your-password"
  db: 0

bot_detect:
  score_threshold: 70     # Score >= 70 = definite bot (blocked)
  challenge_threshold: 40 # Score 40-69 = suspicious (challenge page)

geoip:
  db_path: "/var/lib/klixsor/GeoLite2-City.mmdb"
After editing config.yaml, restart the services for changes to take effect:
systemctl restart klixsor-api klixsor-clickengine

Creating Campaigns

Campaigns are the core of Klixsor. Each campaign has a unique URL that receives traffic and routes it based on your configured flows.

Campaign URL structure

URL
https://track.yourdomain.com/CAMPAIGN-ALIAS?sub_id_1=value&sub_id_2=value

Campaign settings

SettingDescription
AliasURL slug for the campaign (e.g., my-offer)
DomainWhich tracking domain to use
Traffic SourceWhere traffic originates — choose from 33 built-in templates or create a custom source. CAPI-capable sources (Meta, Google, TikTok, Microsoft) support server-side conversion forwarding.
Cost ModelCPC, CPM, CPA, or Revenue Share
UniquenessHow to count unique clicks (by IP, cookie, or both)
Safe PageWhat to show bots/moderators (disabled, redirect, HTML, or proxy)
Campaigns page
Campaign list with click stats, status indicators, and quick actions

Flows & Routing

Each campaign contains one or more flows. Flows determine which landing page and offer a visitor sees based on conditions you define.

Flow types

  • Forced flow — Always used when its conditions match (top priority)
  • Regular flow — Selected by weight among eligible flows
  • Default flow — Fallback when no other flow matches

Flow conditions

Route traffic based on: country, device, OS, browser, language, connection type, ISP, referrer, sub ID values, day of week, hour of day, and more.


Landing Pages

Klixsor supports two types of landing pages:

Redirect landing pages

Klixsor redirects the visitor to your externally hosted landing page URL. The click URL is appended as a parameter so your page can link to the offer.

Local (hosted) landing pages

HTML stored and served directly by Klixsor. Use the Clone from URL feature to import any page:

  1. Click "Clone from URL" in the Landing Pages section
  2. Paste the URL of the page you want to clone
  3. Klixsor fetches the HTML, downloads all assets (images, CSS, JS, fonts) locally, and rewrites URLs so the page is fully self-contained
  4. Edit the page with the built-in visual editor or raw HTML to add {offer_url} placeholders in your CTA buttons

Visual Editor

Local landing pages can be edited with the built-in WYSIWYG visual editor (powered by GrapeJS). Click the paintbrush icon on any local landing page to open it.

  • Drag-and-drop blocks — text, images, links, videos, columns, sections, dividers, and more
  • Style manager — typography, layout, borders, backgrounds, spacing
  • Device preview — desktop, tablet, and mobile views
  • Code editor — switch to raw HTML/CSS when needed
  • Tracking placeholders — insert {click_id}, {offer_url} via dropdown
  • Undo/redo with dirty-state tracking so you never lose changes

Asset cloning

When you clone a page, Klixsor downloads all referenced assets (images, stylesheets, scripts, fonts) to local storage. This means:

  • Your cloned page works even if the original source goes down
  • Page load times are faster since assets are served from your own server
  • CSS files are processed recursively — fonts and images referenced inside CSS are also downloaded

Re-clone & asset management

Cloned pages have two additional actions in the landing page list:

  • Re-clone (refresh icon) — re-fetches the page from the original source URL, downloads fresh assets, and updates the stored HTML. Useful to pick up changes from the source.
  • Manage assets (hard drive icon) — shows the number of downloaded files and total disk usage. You can clear all assets to free disk space. After clearing, images and styles will attempt to load from the original source URLs. Re-clone to download them again.

Available placeholders

PlaceholderReplaced with
{click_id}Unique click identifier
{offer_url}Selected offer URL (for CTA links)
{country}Visitor's country code (US, GB, etc)
{city}Visitor's city name
{device}Device type (desktop, mobile, tablet)
{os}Operating system
{browser}Browser name
{ip}Visitor's IP address
{sub_id_1} ... {sub_id_30}Custom sub ID values
Tip: The landing page cloner is available on Pro and Enterprise plans.

Offers

Offers are the destination URLs where traffic is ultimately sent. Add your affiliate offer URLs with the appropriate tracking parameters.

Offer URL with macros

Example
https://network.com/offer?click_id={click_id}&sub1={sub_id_1}&sub2={sub_id_2}

Klixsor replaces all {placeholder} tokens with actual values when redirecting the visitor.

Affiliate network presets

When creating an offer, select from 36 built-in affiliate network presets that pre-fill the postback URL format and conversion tracking parameters. Supported networks include:

  • CPA Networks: MaxBounty, ClickDealer, Mobidea, Golden Goose, Zeydoo, Adcombo, Clickbooth, ClickBank, CJ Affiliate, A4D, Leadbit, Dr.Cash, Alfaleads, Everad, LosPollos, Toro Advertising, MyLead, CrakRevenue, Adscend Media
  • Affiliate Platforms: ShareASale, FlexOffers, Pepperjam/Ascend, Digistore24, JVZoo, WarriorPlus
  • Ad Network CPA: Adsterra, PropellerAds CPA
  • Custom: Enter any network's postback URL manually
Tip: Each preset includes the correct click ID macro, payout macro, and postback URL format for that network. Just select the preset and Klixsor fills in the details.

Conversion Tracking

Track conversions by adding a postback URL to your affiliate network. When a conversion happens, the network sends a request to Klixsor with the click ID.

Postback URL format

Postback URL
https://track.yourdomain.com/postback?click_id={click_id}&payout={payout}&status=approved

Replace {click_id} and {payout} with your network's corresponding macros.

Conversion parameters

ParameterRequiredDescription
click_idYesThe Klixsor click ID that was passed to the offer
payoutNoRevenue amount (e.g., 2.50)
statusNoapproved, pending, or rejected (default: approved)
transaction_idNoExternal transaction/conversion ID

Conversion API (CAPI)

Server-side conversion forwarding to ad platforms. Send conversion data directly from your server to Meta, Google Ads, TikTok, and Microsoft Ads — bypassing browser limitations and ad blockers.

Why CAPI matters

In the post-iOS 14 world, browser-based tracking (pixels, cookies) is increasingly unreliable. Ad blockers, ITP, and privacy restrictions can prevent conversion pixels from firing. Server-side conversion forwarding (CAPI) solves this by sending conversion events directly from Klixsor to the ad platform's API in real-time, ensuring your optimization data is complete and accurate.

Result: Higher match rates, better optimization signals for the ad platform's algorithm, and more accurate attribution — all without relying on client-side JavaScript.

How to set it up

  1. Select a CAPI-capable traffic source template — When creating or editing a Traffic Source, choose one of the four supported templates: Facebook Ads, Google Ads, TikTok Ads, or Microsoft Ads
  2. Expand the "Conversion API (CAPI)" section — Below the URL parameters, you'll see a collapsible CAPI configuration panel
  3. Enter your platform credentials — Each platform requires different authentication details (see below)
  4. Save the traffic source — CAPI is now active for all campaigns using this traffic source
  5. Conversions are forwarded automatically — When a postback fires for a click from this traffic source, Klixsor sends the conversion event to the platform API in real-time

Platform-specific setup

Meta / Facebook Ads

FieldWhere to find it
Pixel IDEvents Manager → Data Sources → select your Pixel → Settings → Pixel ID
Access TokenEvents Manager → Data Sources → select your Pixel → Settings → Generate Access Token
Test Event Code (optional)Events Manager → Test Events tab → copy the test code (e.g., TEST12345)

Google Ads

FieldWhere to find it
Customer IDGoogle Ads dashboard → top-right corner (format: 123-456-7890)
Conversion Action IDTools & Settings → Conversions → select action → ID in URL
OAuth CredentialsGoogle Cloud Console → APIs → Credentials → OAuth 2.0 Client ID + Secret + Refresh Token

TikTok Ads

FieldWhere to find it
Pixel CodeTikTok Ads Manager → Assets → Events → Web Events → Pixel Code
Access TokenTikTok Ads Manager → Assets → Events → Web Events → Settings → Generate Access Token

Microsoft Ads

FieldWhere to find it
UET Tag IDMicrosoft Ads → Tools → UET Tags → select your tag → Tag ID

Test event codes

Use test event codes to safely verify your CAPI integration without affecting production data. Meta and TikTok both support test modes:

  • Meta: Enter the Test Event Code from Events Manager → Test Events. Events sent with this code appear in the Test Events tab only and do not affect ad delivery.
  • TikTok: Use the test mode toggle in your pixel settings to verify events before going live.

Remove the test event code when you're ready to go live.

Event mapping

Klixsor automatically maps conversion statuses to platform-specific event names:

Klixsor StatusMetaGoogle AdsTikTokMicrosoft
sale / approvedPurchaseConversionCompletePaymentpurchase
leadLeadConversionSubmitFormsignup
installLeadConversionDownloadinstall
Important: CAPI requires that the original click captured the visitor's IP address and user agent, which Klixsor does automatically. The ad platform uses this data to match the server-side event to the original ad click.

Campaign Cloning

Duplicate any campaign with a single click. Cloning copies the entire campaign configuration — including all flows, routing rules, offer/LP assignments, and weights — into a new campaign.

How to clone

In the Campaigns list, click the clone icon (overlapping squares) in the Actions column for any campaign. A new campaign is created instantly with the name "Original Name (copy)" and a unique URL alias.

Campaign list showing clone button in the actions column

What gets cloned

  • Campaign settings — cost model, uniqueness, rotation method, binding, status
  • All flows — bot filters, regular flows, and default fallbacks with their full configuration
  • Flow conditions — geo, device, OS, browser, language, and other targeting rules
  • Offer & LP assignments — all offers and landing pages with their weights
  • Optimization rules — any auto-optimization rules configured on the original campaign

What's NOT cloned

  • Click and conversion data (the clone starts fresh with zero stats)
  • The URL alias (automatically generated as a unique value)

API

POST /api/v1/campaigns/:id/clone

Returns the full new campaign object with all cloned flows.


Auto-Optimization

Automatically adjust offer and landing page weights based on real performance data. The optimization engine runs in the background, evaluating your ClickHouse analytics to shift traffic toward the best-performing variations.

Auto-optimization tab showing rules table with add rule and view logs buttons

How it works

  1. Create an optimization rule on the Optimization tab inside any campaign
  2. Choose what to optimize: offers or landing pages
  3. Select the metric to optimize by: CR (conversion rate), EPC (earnings per click), ROI, or revenue
  4. Choose the action: Adjust weights (proportionally shift traffic) or Pause losers (disable underperformers)
  5. Set the evaluation interval (how often the engine checks, in minutes) and minimum sample size
  6. The engine runs automatically and logs every action it takes

Optimization actions

ActionBehavior
Adjust weightsProportionally increases weight on the best-performing variation and decreases weight on the worst. Smooth, gradual rebalancing.
Pause losersSets the weight to 0 on variations performing below the campaign average. Aggressive — removes underperformers entirely.

Metrics available

MetricDescription
CRConversion rate (conversions / clicks)
EPCEarnings per click (revenue / clicks)
ROIReturn on investment ((revenue - cost) / cost)
RevenueTotal revenue generated

Viewing logs

Click View Logs to see a chronological history of every optimization action taken — which variation was adjusted, the old and new weights, and the metric values that triggered the change.

API

GET    /api/v1/campaigns/:id/optimization     — list rules
POST   /api/v1/campaigns/:id/optimization     — create rule
PUT    /api/v1/campaigns/:id/optimization/:id — update rule
DELETE /api/v1/campaigns/:id/optimization/:id — delete rule
GET    /api/v1/campaigns/:id/optimization/logs — view logs

LP CTR Tracking

Measure landing page click-through rates by tracking two events: page views and CTA clicks. This tells you how effectively each landing page converts visitors into offer clicks.

LP CTR tab showing views, CTA clicks, CTR percentage, and tracking script

How it works

  1. Open any campaign and click the LP CTR tab
  2. Copy the tracking script snippet shown at the bottom
  3. Add the script to your landing pages — it automatically fires a view event on page load
  4. Add a cta_click event to your CTA button's click handler
  5. View results in the LP CTR tab: views, CTA clicks, CTR%, and distribution chart

Tracking script

The LP CTR tab provides a ready-to-use script. Add it to your landing page's HTML:

<script>
// Track page view
fetch('/api/v1/lp-events', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    click_id: new URLSearchParams(location.search).get('click_id'),
    campaign_id: 5,
    event_type: 'view'
  })
});

// On CTA button click:
function trackCTA() {
  fetch('/api/v1/lp-events', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
      click_id: new URLSearchParams(location.search).get('click_id'),
      campaign_id: 5,
      event_type: 'cta_click'
    })
  });
}
</script>

Date range

Use the date picker at the top of the LP CTR tab to filter by time period. The table shows per-landing-page breakdown with a visual distribution bar.

API

POST /api/v1/lp-events                        — track an event
GET  /api/v1/lp-events/ctr?campaign_id=X&date_from=...&date_to=...  — get CTR stats

Smart Alerts

Monitor campaign metrics in real-time and get notified via webhook when thresholds are crossed. Smart Alerts run automatically in the background, checking your analytics data on a configurable schedule.

Smart Alerts page with Rules and History tabs

Setting up an alert

  1. Go to Smart Alerts in the sidebar
  2. Click + New Alert Rule
  3. Configure the rule:
    • Name — descriptive label (e.g., "Low CR warning")
    • Campaign — which campaign to monitor (or all campaigns)
    • Metric — what to watch (clicks, conversions, revenue, CR, ROI, profit, bot clicks)
    • Condition — greater than, less than, or equal to
    • Threshold — the value that triggers the alert
    • Window — time window to evaluate (in minutes, e.g., 60 = last hour)
    • Webhook URL — where to send the notification (Slack, Discord, Telegram, etc.)

Available metrics

MetricDescription
clicksTotal click count in the time window
conversionsTotal conversion count
revenueTotal revenue ($)
crConversion rate (%)
roiReturn on investment (%)
profitNet profit (revenue minus cost)
bot_clicksNumber of clicks flagged as bot traffic

Alert history

Switch to the History tab to see a log of every alert that has fired. Each entry shows the rule name, the metric value that triggered it, the threshold, and when it fired. You can acknowledge alerts to mark them as reviewed.

Webhook format

When an alert fires, Klixsor sends a POST request to your webhook URL with a JSON body:

{"text": "Alert 'Low CR': cr is 1.20 (threshold: 2.00) for campaign 'My Campaign'"}

This format is compatible with Slack, Discord, and most webhook receivers out of the box.

API

GET    /api/v1/alerts            — list alert rules
POST   /api/v1/alerts            — create alert rule
PUT    /api/v1/alerts/:id        — update alert rule
DELETE /api/v1/alerts/:id        — delete alert rule
GET    /api/v1/alerts/history    — view alert history
POST   /api/v1/alerts/:id/ack   — acknowledge an alert

SmartPages — AI-Assisted SEO Content System

SmartPages is Klixsor's built-in content publishing system that turns your domains into fully-functional websites with auto-generated, SEO-optimized articles. Use it for AI-powered content sites, or as pre-landers for your campaigns.

What SmartPages does: Fetches news from RSS feeds, rewrites articles with AI, publishes them on your domains with proper SEO (sitemap, schema.org, meta tags), and optionally integrates with your campaigns to route visitors through your traffic flows.
SmartPages live site example

A SmartPages site running on a custom domain with the News theme

SmartPages Setup

Follow these steps to get your first SmartPages site up and running.

Step 1: Enable SmartPages

Go to SmartPages → Settings and enable the system. You'll need an OpenAI API key for AI article rewriting.

SmartPages settings
  • Enabled: Toggle SmartPages on/off
  • OpenAI API Key: Required for AI-powered article rewriting
  • Rewrite Model: Choose between GPT-4o (higher quality) or GPT-4o-mini (faster/cheaper)
  • Fetch Interval: How often to check RSS feeds for new content (default: 30 minutes)
  • Articles Per Fetch: Maximum articles to pull per feed per cycle

Step 2: Add Content Sources

Go to SmartPages → Sources to add RSS feeds. SmartPages will automatically fetch articles from these feeds.

SmartPages sources
  • Name: Descriptive name for the source
  • RSS URL: The feed URL (e.g. https://feeds.bbci.co.uk/news/rss.xml)
  • Category: Articles from this source will be tagged with this category
  • Active: Enable/disable individual sources
Tip: Add multiple sources across different categories (Technology, Business, Health, etc.) to build a diverse content site. Use category filtering on domains to show only relevant articles.

Step 3: Add a Domain

Go to SmartPages → Domains, add your domain, and set its Content Mode to "SmartPages".

SmartPages domain management
  1. Point your domain's DNS (A record or CNAME) to your server's IP address
  2. In Klixsor, add the domain under Domains or use Bulk Import
  3. Set Content Mode to SmartPages
  4. Click Setup to configure Nginx + SSL (automatic via Let's Encrypt)
  5. Wait a few seconds — your site is live!

Domain Configuration Options

FieldDescription
Content ModeSet to "SmartPages" to serve articles on this domain
CategoryFilter which articles appear — select a specific category or "All categories"
CampaignLink a campaign for traffic monetization (optional)
IntegrationCTA Button: Shows a call-to-action banner. JS Script: Injects campaign's tracking.js to route visitors through flows

Managing Articles

The Articles tab shows all fetched and rewritten articles with their status.

SmartPages articles management

Article Statuses

  • Pending: Fetched from RSS, waiting for AI rewrite
  • Rewriting: Currently being processed by the AI model
  • Published: Live on your SmartPages domain(s)
  • Failed: Rewrite failed — check the error and retry

Article Actions

  • Edit: Modify title, body, meta description, slug, or category
  • Regenerate: Re-run the AI rewrite with updated prompts
  • Delete: Remove the article permanently
  • Bulk Actions: Select multiple articles to publish, unpublish, regenerate, or delete

Keyword-Based Generation

Instead of relying only on RSS feeds, you can generate articles from specific keywords. Go to SmartPages → Keywords.

SmartPages keywords
  1. Click Add Keywords and enter your target keywords (one per line)
  2. Select a category and target domain
  3. Click Generate to trigger AI article creation for pending keywords
  4. Articles are generated with SEO-optimized titles, meta descriptions, and slugs
Tip: Assign keywords to silos (see below) to create topically organized content clusters that rank better in search engines.

Site Configuration

Customize how your SmartPages site looks. Go to SmartPages → Site Config and select a domain.

SmartPages site configuration

Branding

  • Site Name: Displayed in the header and page titles
  • Tagline: Subtitle shown next to the site name
  • Logo URL: Custom logo image (replaces text title)
  • Primary/Secondary Colors: Theme accent colors

Theme Selection

Choose from 4 built-in themes that control the overall look and layout:

  • News: Magazine-style with large hero, 3-column grid, dark header
  • Blog: Clean, single-column layout ideal for long-form content
  • Niche: Review/affiliate style with prominent CTAs and sidebar
  • Authority: Professional multi-column layout with silo navigation

Navigation & Footer

  • Nav Links: Custom navigation menu items
  • Footer Columns: Configurable footer with multiple columns of links
  • Custom HTML: Inject custom code in <head> or before </body>

Sidebar Widgets

  • Recent Posts: Latest published articles
  • Categories: Article category list with counts
  • CTA Box: Custom call-to-action with button
  • Custom HTML: Any HTML content

Silos & Content Organization

Silos let you organize articles into topical clusters — a proven SEO strategy. Each silo has a pillar article and supporting articles that interlink. Go to SmartPages → Silos.

SmartPages silos management

Creating a Silo

  1. Click New Silo
  2. Enter a name (e.g. "Best VPN Reviews") — the slug auto-generates
  3. Add a description and optionally set a pillar article
  4. Click Manage Articles to assign articles to the silo

Managing Silo Articles

Click the article count or the Layers icon to open the article management panel:

  • Top section: Articles currently in the silo — select and remove if needed
  • Bottom section: All available articles with search, category filter, and silo status filter
  • Select articles and click Add to silo to assign them
  • Articles can be moved between silos (reassigned from another silo)

Internal Linking

Click the Link icon on a silo to auto-build internal links:

  • Pillar → Supporting: The pillar article links to all supporting articles
  • Supporting → Pillar: Each supporting article links back to the pillar
  • Supporting → Supporting: Cross-links between related articles in the silo
Internal links are injected automatically into article body text during rendering — no manual HTML editing needed.

Silo Pages

Each silo gets its own page at /silo/{slug} (e.g. /silo/best-vpn-reviews). This page features the pillar article prominently and lists all supporting articles below.

Campaign Integration

SmartPages can integrate with your Klixsor campaigns to monetize traffic. There are two integration modes:

CTA Button Mode

Adds a call-to-action banner on article pages that links to your campaign's tracking URL. Visitors who click the CTA are routed through the campaign's normal flow (bot detection, offer rotation, etc.).

Good for: affiliate content sites where you want the visitor to read the article first, then click through to the offer.

JS Script Mode (Full Flow Routing)

Injects the campaign's tracking.js on every page. The script automatically:

  1. Registers a click through your campaign's flow pipeline
  2. Runs bot detection — if a bot is detected, it can stay on the page (if your forced flow is set to "do nothing") or be redirected to a safe page
  3. Routes real visitors through your campaign's regular/default flows
  4. Redirects visitors to the offer URL per your flow configuration
  5. Decorates external links with click IDs for conversion attribution

Good for: cloaking setups where you want search engines to see content but real visitors to be redirected to offers.

Setting Up Campaign Integration

  1. Create a campaign with at least one offer and a default flow
  2. In SmartPages → Domains, select the campaign in the "Campaign" column
  3. Choose integration mode: CTA Button or JS Script
  4. The integration is active immediately — clicks will appear in your Click Log
Important: For JS Script mode, make sure your campaign has a tracking domain configured (not the same as your SmartPages domain). The script is loaded from the tracking domain to avoid cross-origin issues.

SEO Features

SmartPages is built for search engine optimization out of the box:

Automatic SEO

  • XML Sitemap: Auto-generated at /sitemap.xml with all articles, categories, silos, and legal pages
  • robots.txt: Properly configured to allow crawling and point to sitemap
  • Schema.org Markup: Article, Organization, and BreadcrumbList structured data on every page
  • Open Graph Tags: Full og:title, og:description, og:image, og:type for social sharing
  • Canonical URLs: Prevents duplicate content issues
  • Meta Descriptions: AI-generated meta descriptions for every article
  • Breadcrumbs: Hierarchical navigation showing Home → Category → Article

Legal Pages

Every SmartPages site automatically includes:

  • Privacy Policy (/privacy-policy) — GDPR and CCPA compliant
  • Terms of Service (/terms) — Standard terms covering content usage
  • Cookie Consent Banner — GDPR-compliant cookie notice with Accept/Decline

These pages use your site name and domain automatically — no manual configuration needed. Legal links appear in every page footer.

Image Optimization

SmartPages automatically upgrades thumbnail images from RSS feeds to high-resolution versions. For example, BBC feed images are upgraded from 240px to 960px width for crisp display on all devices.

Bot Detection — How It Works

Klixsor uses a multi-signal scoring system to detect bots. Every click is scored from 0 (human) to 100 (definite bot) using 11 independent detection signals.

Bot Management
Bot Management dashboard with analytics, traffic trend, and category breakdown

Detection signals

  • IP reputation — Checked against 25 auto-synced datacenter, cloud, and VPN/Tor IP lists (+40 score)
  • User agent analysis — Known bot UAs, suspicious patterns, empty/missing UA (+25-30 score)
  • Header anomalies — Missing Accept-Language, unusual Accept header (+5-10 score)
  • Header order fingerprint — Detects non-browser HTTP header ordering (+10 score)
  • DNS verification — Reverse DNS lookup for claimed crawlers (Googlebot, Bingbot) (+10 for fake bots)
  • Datacenter IP detection — Known cloud/datacenter ASN matching (+20 score)
  • Proxy/VPN detection — Anonymous proxy and VPN IP identification (+15 score)
  • Ad review referrer — Detects traffic from ad platform review systems (+15 score)
  • Prefetch detection — Identifies browser prefetch/prerender requests (+20 score)
  • JS fingerprint challenge — Validates browser fingerprint data from JS challenges (-15 for valid, +15-20 for invalid)

Score thresholds

ScoreClassificationDefault action
0 – 39HumanNormal routing
40 – 69SuspiciousChallenge page (configurable)
70 – 255BotSafe page or block

Bot Rules

Create custom rules to override bot scoring based on specific conditions. Rules are evaluated in priority order (lower number = higher priority) and can be scoped globally, per domain, or per campaign.

Conditions

Each rule can have multiple conditions combined with AND logic. Available condition types:

ConditionOperatorsDescription
bot_scoreeq, gt, gte, lt, lteNumeric bot score (0-100)
is_boteqBoolean — whether score exceeds threshold
bot_categoryeq, neqCategory: human, ad_review, search_engine, headless, etc.
ipeq, containsIP address or CIDR range
user_agentcontainsUser-Agent substring match
countryeq, neq2-letter country code
device_typeeq, neqdesktop, mobile, tablet
oseq, neqOperating system name
browsereq, neqBrowser name
referrercontainsReferrer URL substring
languageeq, neqBrowser language code
is_proxyeqBoolean — proxy/VPN detection
visit_counteq, gt, gte, lt, lteNumber of visits from this IP to this campaign

Actions

  • Allow — Force-allow regardless of bot score
  • Block — Return 403 Forbidden
  • 404 — Return 404 Not Found
  • Safe page — Show the campaign's safe page
  • Redirect — Send to a custom URL (301/302/meta refresh)
  • Show HTML — Serve custom HTML content
  • Show text — Serve plain text response
  • JS Challenge — Serve a JavaScript fingerprint challenge page (see JS Fingerprint Challenge)
  • Tag only — Mark as bot in analytics but allow through
  • Fake page — Serve a decoy page
  • Honeypot — Serve a honeypot trap page
  • Rate limit — Throttle requests from the IP
  • Delay — Add artificial delay before response
Custom bot rules are available on the Enterprise plan. All plans include the built-in bot scoring engine.

IP Lists

Klixsor auto-syncs 25 IP lists from datacenter providers, cloud platforms, and VPN services daily:

Search engine & ad platform bots (allow lists)

  • Googlebot, Google Ads, Google Special Crawlers
  • Bingbot, Applebot
  • Facebook/Meta

Datacenter & cloud providers (challenge lists)

  • AWS, Google Cloud (GCP), Microsoft Azure
  • DigitalOcean, Oracle Cloud (OCI), Hetzner
  • OVH, Vultr, Linode, Scaleway, Cloudflare

VPN & Tor providers (block lists)

  • Tor Exit Nodes (from torproject.org)
  • NordVPN, ExpressVPN, Surfshark
  • CyberGhost, Private Internet Access (PIA), Mullvad
IP Lists
25 auto-synced IP lists with entry counts and sync status

Lists sync automatically on first install and every 24 hours thereafter. Each list has a configurable type:

  • Allow — Known good bots (Googlebot, etc.) — allows them through
  • Challenge — Datacenter IPs — triggers a challenge or increases bot score
  • Block — VPN/Tor IPs — blocks or redirects to safe page

You can also add custom IP lists manually with individual IPs or CIDR ranges.


VPN & Tor Detection

Klixsor includes built-in detection for major VPN providers and the Tor network. These IP lists are auto-synced daily from authoritative sources.

How it works

  • Tor Exit Nodes — Synced directly from the Tor Project's bulk exit list (check.torproject.org)
  • VPN Providers — IP ranges are fetched via RIPE Stat ASN prefix announcements for each provider's registered ASN

Supported VPN providers

ProviderASNDetection method
NordVPNAS212238RIPE Stat prefix announcements
ExpressVPNAS394711RIPE Stat prefix announcements
SurfsharkAS211298RIPE Stat prefix announcements
CyberGhostAS9009RIPE Stat prefix announcements
Private Internet AccessAS26347RIPE Stat prefix announcements
Mullvad VPNAS198093RIPE Stat prefix announcements
Tor NetworkExit node list from torproject.org

Configuration

VPN and Tor lists are enabled by default with block type. You can change the behavior per list in Bot Management → IP Lists:

  • Set to Block to deny VPN/Tor traffic
  • Set to Challenge to show a JS challenge page instead
  • Disable individual lists if you don't want to block specific VPN providers
VPN/Tor IP lists contribute +40 to the bot score when a visitor's IP matches. Combined with other signals, this typically results in automatic blocking.

JS Fingerprint Challenge

The JavaScript fingerprint challenge is an advanced bot detection action that serves a "Checking your browser..." page, collects real browser fingerprint data, and uses it to verify whether the visitor is human.

How it works

  1. When a bot rule triggers the challenge_js action, Klixsor serves an HTML page with embedded JavaScript
  2. The JavaScript collects 15+ browser signals including timezone, screen resolution, canvas rendering, WebGL capabilities, and audio context
  3. These signals are encoded and stored in a _kfp cookie
  4. After 1.5 seconds, the visitor is redirected back to the same URL with a _bc=1 parameter
  5. On the second request, the bot detector reads the fingerprint cookie and validates the data

Fingerprint signals collected

  • Timezone, language, platform
  • Hardware concurrency, device memory, touch points
  • Screen width/height, color depth, device pixel ratio
  • Canvas rendering hash (unique per GPU/driver)
  • WebGL renderer and vendor strings
  • Audio context FFT size
  • WebGL support, PDF viewer detection

Scoring impact

ScenarioScore impact
Valid fingerprint with 4+ real browser signals-15 (reduces bot score)
Cookie present but fingerprint data is invalid+15 (increases bot score)
Challenge redirect detected but no fingerprint cookie+20 (headless bot)

Setting up a JS challenge rule

Go to Bot Management → Bot Rules and create a rule:

  1. Set a condition like bot_score gte 30 (suspicious visitors)
  2. Select action JavaScript Challenge
  3. Save the rule

Headless bots (Puppeteer, Selenium) typically fail the challenge because they either can't execute JavaScript or produce detectable fingerprint anomalies.

Note: The JS challenge adds ~1.5 seconds of latency for the challenged visitor. Use it selectively (e.g., only for suspicious scores, not all traffic).

Visit Count Rules

The visit_count condition lets you create bot rules based on how many times an IP has visited a specific campaign. This is useful for detecting aggressive scrapers, click fraud, and repeated bot visits.

How it works

  • Every click increments a per-IP, per-campaign counter stored in Redis
  • The counter uses the campaign's uniqueness TTL as the expiration window (default: 24 hours)
  • Bot rules can match on this counter using numeric operators

Example rules

ConditionActionUse case
visit_count gte 10Challenge JSChallenge IPs with 10+ visits
visit_count gte 50BlockBlock aggressive scrapers
visit_count gte 5 + bot_score gte 20Safe pageShow safe page to repeat suspicious visitors

Setting it up

  1. Go to Bot Management → Bot Rules
  2. Create a new rule
  3. Add a condition with type visit_count, operator gte, and your threshold value
  4. Choose an action (block, challenge, redirect, etc.)
  5. Set the priority (lower = evaluated first)

Domain Health Monitoring

Klixsor automatically monitors the health of all your tracking domains every 5 minutes. If a domain goes down or becomes degraded, you'll see it immediately in the Domains page.

Domain health monitoring
Domains page showing real-time health status with response time

Health statuses

StatusMeaning
HealthyDomain responds with HTTP 2xx-4xx and latency under 5 seconds
DegradedDomain responds with HTTP 5xx or latency exceeds 5 seconds
DownDomain is unreachable (connection refused, DNS failure, timeout)
UnknownNot yet checked (newly added domain)

What's monitored

  • HTTP status code — The response code from hitting the domain root URL
  • Response latency — Time to first byte in milliseconds
  • SSL validity — Whether the HTTPS certificate is valid (if SSL is enabled)
  • Error details — Specific error message when the domain is down

Manual health check

Click the pulse icon next to any domain's health badge to run an on-demand health check. The result updates immediately in the UI.

API endpoint

bash
curl -X POST https://admin.yourdomain.com/api/v1/domains/1/check-health \
  -H "Authorization: Bearer YOUR-JWT-TOKEN"

# Response includes updated health fields:
# { "id": 1, "name": "track.example.com", "health_status": "healthy",
#   "health_http_code": 200, "health_latency_ms": 42, ... }

Updating Klixsor

Updates are safe and non-destructive. All your data, configuration, and credentials are preserved.

Check for updates

Go to Settings in the admin panel sidebar. The Version card shows:

  • Current Version — the version running on your server
  • Latest Version — the newest release available
  • Update Available indicator — shown when a newer version exists

If an update is available, the Settings page displays the update command you need to run.

Update to the latest version

SSH into your server and run:

bash
curl -sSL https://klixsor.com/install.sh | bash -s -- --update

What happens during an update

  1. Backup — PostgreSQL database dump + config files saved to /var/lib/klixsor/backups/
  2. Stop — Click engine and API gracefully stopped
  3. Download — New binaries downloaded and validated (ELF header check prevents corrupt downloads)
  4. Migrate — New database migrations applied (idempotent, safe to re-run)
  5. Start — Services restarted
  6. Verify — Health check confirms everything is running
  7. Rollback — If the health check fails, old binaries and database are automatically restored

What's preserved

  • All campaign, domain, and user data
  • Click history and conversion data
  • Configuration file (config.yaml)
  • Database passwords and JWT secret (.env)
  • License key
  • Nginx configs and SSL certificates
  • Firewall rules
  • Admin credentials

Update to a specific version

bash
curl -sSL https://klixsor.com/install.sh | bash -s -- --update --version 1.2.0

Skip backup (faster, not recommended)

bash
curl -sSL https://klixsor.com/install.sh | bash -s -- --update --no-backup
Downtime: Updates typically take 30-60 seconds. Traffic is not processed during this window. Schedule updates during low-traffic periods.

Settings Page

The Settings page (accessible from the sidebar) provides a system overview with four information cards:

GeoIP Databases (Required)

Klixsor uses MaxMind GeoLite2 databases for precise geolocation tracking (Country, City, ISP). You must provide your own free license key after installation to enable this functionality.

  • Sign up for a free MaxMind account (the signup link is provided directly in the dashboard).
  • Generate a License Key from your MaxMind account dashboard.
  • Paste the key into the GeoIP panel and click Update Now to instantly download the databases.
GeoIP Settings Card
GeoIP Databases configuration card in Settings

License

  • Status — Active, Invalid, or Grace Period
  • Plan — Your current subscription tier (Starter, Pro, Enterprise)
  • License Key — Masked display of your license key
  • Expires — License expiration date with a warning if expiring soon

Usage & Limits

Visual progress bars showing your current usage against plan limits:

  • Campaigns — current / maximum campaigns
  • Domains — current / maximum domains
  • Users — current / maximum users

Bars turn yellow at 70% and red at 90% usage. "Unlimited" is shown for Enterprise plans.

Version

  • Current Version — the version running on this server
  • Latest Version — the newest version available from klixsor.com
  • Update Available — indicator with the update command when a new version exists

Plan Features

Shows which features are included in your plan (e.g., landing page cloner, API access, custom bot rules). Only displayed when features are restricted by your plan.

Settings page
Settings page showing license status, usage limits, version info, and plan features

Backups & Restore

Automatic backups

Every update creates an automatic backup at /var/lib/klixsor/backups/klixsor_backup_YYYYMMDD_HHMMSS/. The 5 most recent backups are kept.

Manual backup

bash
# PostgreSQL dump
docker exec klixsor-postgres pg_dump -U klixsor -d klixsor \
  --format=custom -f /tmp/klixsor_backup.dump
docker cp klixsor-postgres:/tmp/klixsor_backup.dump ./klixsor_backup.dump

# Config files
cp /opt/klixsor/configs/config.yaml ./config.yaml.bak
cp /opt/klixsor/.env ./.env.bak

Restore from backup

bash
# Stop services
systemctl stop klixsor-api klixsor-clickengine

# Restore PostgreSQL
docker cp klixsor_backup.dump klixsor-postgres:/tmp/restore.dump
docker exec klixsor-postgres pg_restore -U klixsor -d klixsor \
  --clean --if-exists /tmp/restore.dump

# Restore config
cp config.yaml.bak /opt/klixsor/configs/config.yaml

# Restart
systemctl start klixsor-api klixsor-clickengine

License Management

How licensing works

  • Your license key is stored at /opt/klixsor/license.key
  • Klixsor validates the license with the Klixsor license server every 6 hours
  • If the server is unreachable, a 72-hour grace period allows continued operation
  • Plan limits (campaigns, domains, users) are enforced based on your subscription tier

Update your license key

bash
# Method 1: Via the update script
curl -sSL https://klixsor.com/install.sh | bash -s -- --update NEW-LICENSE-KEY

# Method 2: Manually
echo "NEW-LICENSE-KEY" > /opt/klixsor/license.key
systemctl restart klixsor-api klixsor-clickengine

Plan limits

ResourceStarterProEnterprise
Campaigns1050Unlimited
Domains310Unlimited
Users15Unlimited
Clicks/day100k1MUnlimited
Data retention6 months12 monthsUnlimited
Landing cloner
API access
Custom bot rules

Troubleshooting

Services won't start

bash
# Check service status and logs
systemctl status klixsor-api
journalctl -u klixsor-api -n 50 --no-pager

systemctl status klixsor-clickengine
journalctl -u klixsor-clickengine -n 50 --no-pager

# Check if Docker containers are running
docker ps

Port already in use

bash
# Find what's using port 8081
fuser 8081/tcp
# Kill the process
fuser -k 8081/tcp
# Restart
systemctl restart klixsor-api

Database connection failed

bash
# Check if PostgreSQL is running
docker exec klixsor-postgres pg_isready -U klixsor

# Restart Docker containers
cd /opt/klixsor && docker compose --env-file .env up -d

# Verify password matches config
grep password /opt/klixsor/configs/config.yaml
grep POSTGRES_PASSWORD /opt/klixsor/.env

License validation errors

bash
# Check license key
cat /opt/klixsor/license.key

# Test connectivity to license server
curl -s https://klixsor.com/api/license/validate

# Check logs for license errors
journalctl -u klixsor-api | grep license

Bot IP lists empty

Lists sync automatically on first install. If they're empty:

bash
# Restart the API to trigger sync
systemctl restart klixsor-api

# Check logs for sync status
journalctl -u klixsor-api | grep "bot.*sync"

Need help?

Contact us at support@klixsor.com with your server's API logs and we'll help you get running.


API Authentication

The Klixsor API uses JWT tokens. Obtain a token by logging in, then include it in the Authorization header.

Login

bash
curl -X POST https://admin.yourdomain.com/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"login": "admin", "password": "your-password"}'

# Response:
# { "token": "eyJhbGciOi...", "refresh_token": "..." }

Authenticated request

bash
curl https://admin.yourdomain.com/api/v1/campaigns \
  -H "Authorization: Bearer YOUR-JWT-TOKEN"
API access is available on Pro and Enterprise plans. See the endpoints reference for all available routes.

API Endpoints

All endpoints are under /api/v1/ and require JWT authentication (except login).

MethodPathDescription
POST/auth/loginLogin, get JWT token
POST/auth/refreshRefresh JWT token
GET/auth/meCurrent user info
Campaigns
GET/campaignsList campaigns
POST/campaignsCreate campaign
GET/campaigns/:idGet campaign
PUT/campaigns/:idUpdate campaign
DELETE/campaigns/:idDelete campaign
POST/campaigns/:id/cloneClone campaign
Optimization
GET/campaigns/:id/optimizationList optimization rules
POST/campaigns/:id/optimizationCreate optimization rule
PUT/campaigns/:id/optimization/:ruleIdUpdate optimization rule
DELETE/campaigns/:id/optimization/:ruleIdDelete optimization rule
GET/campaigns/:id/optimization/logsView optimization logs
Smart Alerts
GET/alertsList alert rules
POST/alertsCreate alert rule
PUT/alerts/:idUpdate alert rule
DELETE/alerts/:idDelete alert rule
GET/alerts/historyView alert history
POST/alerts/:id/ackAcknowledge alert
LP CTR Tracking
POST/lp-eventsTrack LP event (view or cta_click)
GET/lp-events/ctrGet LP click-through rates
Offers
GET/offersList offers
POST/offersCreate offer
PUT/offers/:idUpdate offer
DELETE/offers/:idDelete offer
Domains
GET/domainsList domains
POST/domainsAdd domain
PUT/domains/:idUpdate domain
DELETE/domains/:idDelete domain
POST/domains/:id/setup-sslProvision SSL certificate
POST/domains/:id/check-healthRun on-demand health check
Landing Pages
GET/landing-pagesList landing pages
POST/landing-pagesCreate landing page
POST/landing-pages/clone-urlClone page from URL (downloads assets locally)
PUT/landing-pages/:idUpdate landing page
DELETE/landing-pages/:idDelete landing page
POST/landing-pages/:id/duplicateDuplicate landing page
POST/landing-pages/:id/recloneRe-clone from original source URL
GET/landing-pages/:id/assetsGet asset file count and disk usage
DELETE/landing-pages/:id/assetsClear downloaded assets
Reports
POST/reports/queryRun analytics query
GET/reports/dashboardDashboard stats
GET/reports/click-logRaw click log
Conversions
GET/conversionsList conversions

All list endpoints support ?page=1&per_page=50&sort_by=id&sort_dir=desc&search=term query parameters.


Postback URL

Configure this postback URL in your affiliate network to track conversions:

Postback URL
https://track.yourdomain.com/postback?click_id=REPLACE&payout=REPLACE&status=approved

Replace REPLACE with your network's macros for click ID and payout.


Cost Sync — Ad Network Spend Data

Cost Sync pulls advertising spend data from your ad network accounts (Facebook/Meta, Google Ads, TikTok Ads) directly into Klixsor. This enables true ROI and profit calculations by combining your actual ad spend with Klixsor's conversion revenue data.

What Cost Sync does: Automatically fetches campaign-level spend, impressions, and click data from your ad accounts every 15 minutes. This data is stored in ClickHouse alongside your click data and appears in Reports as new metrics: Ad Spend, True Profit, True ROI, True CPA, and more.
Cost Sync overview page

The Cost Sync page showing connections to ad network accounts

Why Use Cost Sync?

Without Cost Sync, Klixsor calculates cost from the cost parameter in your tracking URLs (e.g., &cost={cost_per_click}). This works well for per-click cost tracking, but has limitations:

  • Not all traffic sources pass cost in the URL
  • URL-based cost may not match what the ad network actually charged
  • No impression data — you can't calculate CPM or CTR from the ad network's perspective
  • No way to see total account spend for campaigns not yet linked to Klixsor

Cost Sync solves all of these by pulling the actual spend directly from the ad network's reporting API.

Supported Platforms

PlatformAPI UsedData Pulled
Meta / FacebookMarketing API v21.0 (Insights)Campaign, Ad Set, Ad level: spend, impressions, clicks
Google AdsGoogle Ads API v17 (SearchStream)Campaign, Ad Group level: cost, impressions, clicks
TikTokTikTok Marketing API v1.3 (Reports)Campaign, Ad Group, Ad level: spend, impressions, clicks

Prerequisites

Before setting up Cost Sync, you need:

1. A Traffic Source with CAPI Configured

Cost Sync reuses the API tokens you already configured for Conversion API (CAPI) on your traffic source. If you haven't set up CAPI yet:

  1. Go to Traffic Sources and create or edit a source (e.g., "Facebook Ads")
  2. Select the matching template (Facebook Ads, Google Ads, or TikTok Ads)
  3. Expand the Conversion API (CAPI) section
  4. Enable CAPI and enter your platform credentials (access tokens, pixel IDs, etc.)
  5. Save the traffic source
Tip: You don't need to use CAPI for conversions to use Cost Sync. The tokens are shared, but the features work independently.

2. Your Ad Account ID

You'll need your ad account ID from each platform:

PlatformAccount ID FormatWhere to Find It
Meta / Facebookact_123456789Facebook Business Manager → Business Settings → Ad Accounts. Include the act_ prefix.
Google Ads1234567890Google Ads dashboard → top-right corner shows your account number (remove dashes). This is your Customer ID.
TikTok1234567890TikTok Ads Manager → click your profile icon → Advertiser ID.

3. Required API Tokens by Platform

PlatformRequired Tokens (set in Traffic Source CAPI config)
MetaAccess Token — A system user token or long-lived user token with ads_read permission. Generate in Business Manager → System Users.
Google AdsRefresh Token, Client ID, Client Secret, Developer Token, Customer ID — Set up via Google Ads API credentials in your Google Cloud project.
TikTokAccess Token — Generate via TikTok Marketing API developer portal with Ad Account Management and Reporting scopes.

Setting Up Cost Sync

Once your traffic source has CAPI tokens configured, setting up Cost Sync takes about 30 seconds.

Step 1: Go to Cost Sync

Click Cost Sync in the left sidebar (the $ icon).

Step 2: Add a Connection

Click the + Add Connection button. Fill in the modal:

Cost Sync new connection modal

Creating a new cost sync connection for a Facebook Ads account

FieldDescription
Traffic SourceSelect the traffic source that has CAPI tokens configured for this platform. Required.
PlatformChoose the ad platform: Meta/Facebook, Google Ads, or TikTok. Must match the CAPI config on the selected traffic source.
Account IDYour ad account ID from the platform. For Facebook, include the act_ prefix. Required.
Account NameOptional label for your reference (e.g., "Main FB Account" or "US Campaigns").
Sync IntervalHow often to pull data, in minutes. Default is 60. Minimum is 5. The worker also runs a baseline cycle every 15 minutes.
EnabledToggle the connection on/off without deleting it.

Step 3: Verify the Sync

After creating the connection, you can:

  • Click the play button (▶) in the Actions column to trigger an immediate sync
  • Or click Sync All Now to sync all enabled connections
  • Check the Status column — it should show a green "Success" badge
  • The Rows column shows how many cost records were synced
Important: Cost Sync pulls data for today and yesterday on each cycle. This ensures late-arriving spend data (which ad networks sometimes delay) is always captured. Historical backfill is not performed — data collection starts from the day you create the connection.

Platform-Specific Setup

Meta / Facebook Ads

  1. In Traffic Sources, create a source using the "Facebook Ads" template
  2. In the CAPI section, enter your Meta Access Token (system user token with ads_read permission)
  3. In Cost Sync, add a connection with platform "Meta / Facebook"
  4. Enter your Ad Account ID (format: act_123456789)
Token permissions: Your Meta access token needs the ads_read permission to pull cost data. If you already use it for CAPI conversions, you may need to add this permission. System user tokens are recommended for long-term stability.

Google Ads

  1. In Traffic Sources, create a source using the "Google Ads" template
  2. In the CAPI section, enter your Customer ID, Developer Token, Client ID, Client Secret, and Refresh Token
  3. In Cost Sync, add a connection with platform "Google Ads"
  4. The Account ID field should match your Customer ID (digits only, no dashes)
Google specifics: Cost Sync uses the Google Ads API SearchStream with GAQL queries. Cost is reported in micros (1,000,000 = $1.00) and automatically converted to USD. The Developer Token must have at least Basic access level.

TikTok Ads

  1. In Traffic Sources, create a source using the "TikTok Ads" template
  2. In the CAPI section, enter your TikTok Access Token
  3. In Cost Sync, add a connection with platform "TikTok"
  4. Enter your Advertiser ID as the Account ID

Monitoring & Troubleshooting

Connection Status

Each connection shows a status badge in the table:

  • Never (gray) — No sync has been attempted yet. Click the play button to trigger one.
  • Success (green) — Last sync completed successfully. Shows the number of rows synced.
  • Error (red) — Last sync failed. Hover over or check the activity feed for the error message.

Activity Feed

Click the Sync Activity section below the table to expand the activity log. It shows timestamped entries for each sync cycle:

  • Info (gray) — Normal operations like "Starting cost sync cycle" or row counts per date
  • Success (green) — Completed syncs with total row counts
  • Error (red) — Failed syncs with error details (e.g., invalid token, API rate limit)

Common Errors

ErrorCauseFix
"no capi_config"The linked traffic source doesn't have CAPI configuredEdit the traffic source and set up CAPI credentials
"401 Unauthorized" or "Invalid token"Access token expired or lacks permissionsGenerate a new token and update the traffic source CAPI config
"Rate limit exceeded"Too many API requests to the ad platformIncrease the sync interval (e.g., from 15 to 60 minutes)
"Account not found"Wrong ad account ID formatVerify the Account ID format matches the platform (see Prerequisites)
"ClickHouse insert failed"Database connection issueCheck that ClickHouse is running and accessible

Using Cost Data in Reports

Once Cost Sync is pulling data, new metrics become available in Reports:

New Ad Cost Metrics

MetricDescription
Ad SpendTotal spend reported by the ad network (from the ad_costs table)
Ad ImpressionsTotal impressions reported by the ad network
Ad ClicksTotal clicks reported by the ad network
Ad CPCCost per click from the ad network (Ad Spend ÷ Ad Clicks)
Ad CPMCost per thousand impressions (Ad Spend ÷ Ad Impressions × 1000)
Ad CTRClick-through rate from the ad network (Ad Clicks ÷ Ad Impressions × 100)
True ProfitConversion Revenue minus Ad Spend (actual profit from the ad network's perspective)
True ROI(Revenue - Ad Spend) / Ad Spend × 100 — your real return on investment
True CPAAd Spend ÷ Conversions — how much the ad network actually charged per conversion

Cost vs. Ad Spend

Klixsor now has two types of cost data. Understanding the difference is important:

Cost (existing)Ad Spend (new)
SourceURL parameter (&cost=0.05) or campaign CPC/CPM configAd network reporting API (Cost Sync)
GranularityPer clickPer campaign/day (aggregated by ad network)
AccuracyDepends on traffic source passing correct valueExact — matches your ad network invoice
MetricsCost, CPC, CPA, Profit, ROIAd Spend, Ad CPC, Ad CPM, True Profit, True ROI, True CPA
Recommendation: Use the existing Cost metric for per-click analysis and the new Ad Spend / True ROI metrics for campaign-level profitability analysis. Together, they give you the complete picture.

How Matching Works

Cost Sync data is matched to your clicks using three keys:

  1. Traffic Source ID — the Klixsor traffic source linked to the Cost Sync connection
  2. Date — the day the ad spend occurred
  3. External Campaign ID — the ad_campaign_id parameter from your tracking URL, matched against the campaign ID from the ad network

For matching to work correctly, make sure your tracking URLs include the ad network's campaign ID parameter (e.g., &ad_campaign_id={campaign_id}). The built-in traffic source templates (Facebook, Google, TikTok) handle this automatically via sub_id_2.