Custom Fields and Notifier for YOURLS

April 4, 2026 · View on GitHub

Add configurable custom fields to short links and receive customisable webhook notifications when clicked.

Attach metadata to any short link and trigger workflows when someone clicks it — useful for CRM integration, proposal tracking, marketing automation, and more.

Features

  • Custom Fields — Three fields (cf1, cf2, cf3) out of the box, or define your own
  • Webhook Notifications — Fire an HTTP POST to a per-link URL when a link is clicked
  • Bot Filtering — Automatically block bots (Slack, Facebook, Google, etc.) from inflating click counts and triggering webhooks
  • Click Deduplication — Prevent duplicate webhook notifications from browser prefetch and rapid clicks
  • Dashboard Columns — See your custom field values directly in the YOURLS admin table
  • Admin Settings Page — View plugin status, field configuration, notification log, and bot blocklist
  • Async Webhooks — Notifications fire after the redirect completes, so users experience zero delay

Requirements

  • YOURLS 1.9+
  • PHP 7.4+
  • MySQL 5.7+ or MariaDB 10.3+
  • cURL extension

Installation

  1. Download or clone this repo into your YOURLS plugins directory:
cd /path/to/yourls/user/plugins
git clone https://github.com/belmontdigitalmarketing/custom-fields-and-notifier.git
  1. Activate the plugin in the YOURLS admin panel at Manage Plugins.

  2. The database tables are created automatically on activation.

  3. (Optional, but recommended) Add to your config.php for accurate click tracking:

define('YOURLS_REDIRECT_TYPE', 302);

That's it — the plugin is ready to use with three default fields: cf1, cf2, cf3.

API Usage

Custom field values can only be set via the YOURLS API. The admin panel displays field values in the dashboard columns but does not provide a way to enter or edit them.

Include your custom field values as parameters when creating a short link via the YOURLS API. By default, the available fields are cf1, cf2, and cf3.

curl -X POST "https://your-yourls.com/yourls-api.php" \
  -d "signature=your_signature" \
  -d "action=shorturl" \
  -d "url=https://example.com/proposal" \
  -d "cf1=12345" \
  -d "cf2=John Doe" \
  -d "cf3=some value" \
  -d "notification_url=https://your-webhook.com/endpoint"

The notification_url is a built-in field (always available) that tells the plugin where to send a webhook when the link is clicked.

Retrieving Custom Fields

Use the expand API action:

curl "https://your-yourls.com/yourls-api.php?signature=your_signature&action=expand&shorturl=abc123&format=json"

Response includes all custom fields:

{
  "keyword": "abc123",
  "shorturl": "https://your-yourls.com/abc123",
  "longurl": "https://example.com/proposal",
  "cf1": "12345",
  "cf2": "John Doe",
  "cf3": "some value",
  "notification_url": "https://your-webhook.com/endpoint"
}

Webhook Payload

When a link with a notification_url is clicked, the plugin sends an HTTP POST with this JSON payload. All custom fields are included automatically.

{
  "event": "link_clicked",
  "timestamp": "2026-04-03T12:00:00+00:00",
  "keyword": "abc123",
  "shorturl": "https://your-yourls.com/abc123",
  "longurl": "https://example.com/proposal",
  "destination_url": "https://example.com/proposal",
  "title": "Example Proposal",
  "clicks": 1,
  "ip": "192.168.1.1",
  "user_agent": "Mozilla/5.0...",
  "referrer": "",
  "cf1": "12345",
  "cf2": "John Doe",
  "cf3": "some value",
  "date_created": "2026-04-03 12:00:00"
}

Customization (Optional)

Everything below is optional — the plugin works out of the box with the defaults above.

Custom Field Names

Replace the default cf1/cf2/cf3 fields with meaningful names by adding BMD_CUSTOM_FIELDS to your config.php. Each field has an ID (used in the API and database), a display label (shown in the dashboard), and a type.

define('BMD_CUSTOM_FIELDS', json_encode([
    'contact_id'   => ['label' => 'Contact ID',   'type' => 'text'],
    'contact_name' => ['label' => 'Contact Name', 'type' => 'text'],
    'campaign'     => ['label' => 'Campaign',     'type' => 'text'],
]));

With this configuration, the API parameters become contact_id, contact_name, campaign instead of cf1, cf2, cf3:

curl -X POST "https://your-yourls.com/yourls-api.php" \
  -d "signature=your_signature" \
  -d "action=shorturl" \
  -d "url=https://example.com/proposal" \
  -d "contact_id=12345" \
  -d "contact_name=John Doe" \
  -d "campaign=spring-2026" \
  -d "notification_url=https://your-webhook.com/endpoint"

Fields can be added at any time — the plugin will automatically add new columns to the database. Existing data is never deleted.

All Configuration Options

// Custom field definitions (JSON)
define('BMD_CUSTOM_FIELDS', json_encode([...]));

// Enable debug logging to PHP error log
define('BMD_CF_DEBUG', true);

// Bot filter: block bots from counting clicks (default: true)
define('BMD_BOT_FILTER_ENABLED', true);

// Bot blocklist: comma-separated user agent substrings
define('BMD_BOT_BLOCKLIST', 'Slackbot,facebookexternalhit,Twitterbot,LinkedInBot,WhatsApp');

// Dedup window: seconds to ignore duplicate clicks from same IP (default: 10)
define('BMD_DEDUP_WINDOW', 10);

// Dedup TTL: seconds before old dedup records are purged (default: 3600)
define('BMD_DEDUP_TTL', 3600);

// SSL verification for webhook requests (default: true, set false for local dev only)
define('BMD_SSL_VERIFY', true);

// Use 302 redirects so every click hits the server (recommended)
define('YOURLS_REDIRECT_TYPE', 302);

Bot Filtering

By default, the plugin blocks these bots from counting clicks or triggering webhooks:

Slackbot, Facebook, Twitter/X, LinkedIn, WhatsApp, Telegram, Discord, Google, Bing, Yandex, Baidu, DuckDuckGo, Sogou, Exabot, Internet Archive, Ahrefs, Semrush, Majestic, DotBot, PetalBot, Applebot

Bots still get redirected (so link previews work), but:

  • The click is not counted in YOURLS stats
  • The webhook is not fired

This ensures your click counts and automation triggers reflect real human interactions.

301 vs 302 Redirects

YOURLS defaults to 301 (permanent) redirects, which browsers cache. This means repeat clicks from the same browser won't hit your server — no click counted, no webhook fired.

We recommend 302 (temporary) redirects if you need:

  • Accurate click counts for every visit
  • Webhook notifications on every click
  • The link is for tracking (not SEO)

Add to config.php:

define('YOURLS_REDIRECT_TYPE', 302);

Admin Page

The plugin adds a Custom Fields and Notifier page to the YOURLS admin menu with:

  • Plugin status (tables, debug mode, SSL, bot filter)
  • Custom field configuration and database sync status
  • Bot blocklist display
  • Recent notification log with purge option
  • Configuration reference with copy-ready code snippets

Upgrading from v2

If you previously used the separate "Custom Fields for Links" and "Custom Notifier for Links" plugins:

  1. Deactivate both v2 plugins in YOURLS admin
  2. Activate this plugin (Custom Fields and Notifier)
  3. Your existing data (cf1/cf2/cf3, notification_url) is preserved automatically
  4. Dashboard columns and admin page are immediately available

No database migration is needed — the plugin uses the same custom_fields table.

License

MIT License. See LICENSE for details.

Author

Belmont Digital