WordPress Plugin
The Opportify Fraud Protection plugin brings real-time multi-signal fraud scoring directly into WordPress. It protects form submissions, user registrations, comments, and WooCommerce checkout with invisible, frictionless detection that requires no user interaction.
Unlike the JS Script integration which requires adding code to your pages, the WordPress plugin handles everything automatically once activated. Just install, enter your API keys, and enable the integrations you need.
How It Works
The plugin uses a hybrid client + server approach:
- Client-side — The Opportify JS SDK loads silently via
wp_enqueue_scripts, collecting behavioral signals, device fingerprints, and bot indicators with no visible impact on the user experience. - Server-side — On every form submission, the plugin hooks into the form's validation lifecycle and calls the Fraud Protection API, which analyzes 100+ signals across email risk, IP intelligence, device fingerprinting, and behavioral correlation.
- You decide — Per integration, configure whether to Allow, Flag, or Block at each risk level.
WordPress Page Opportify
────────────────────── ──────────────────────────────────
JS SDK (auto-loaded) ──▶ Session Init (fingerprint, signals)
User fills form ──▶ Behavioral telemetry
User submits form ──▶ Plugin hooks into validation
Plugin calls API ──▶ Risk Engine (score + level)
└─▶ Allow / Flag / Block
Requirements
| Requirement | Version |
|---|---|
| PHP | 8.1+ |
| WordPress | 6.0+ |
| Opportify account | Start free trial |
Installation
From WordPress Admin
- Search for Opportify Fraud Protection in Plugins → Add New, or download from the WordPress Plugin Directory
- Install and activate the plugin
- Navigate to Opportify → Settings
- Enter your Private API Key (used server-side for API calls) and Public Key (used client-side by the JS SDK) from app.opportify.ai
- Enable protection and configure your integrations
Supported Integrations
Forms & Registration
Form integrations hook into each plugin's validation lifecycle. Flag stores risk metadata in the plugin's native entry storage (comment meta, user meta, order meta, or form entry meta) and lets the submission proceed. Block returns a validation error via the plugin's native error mechanism, halting the submission. Integrations marked ❌ for Flag lack a native storage or review mechanism for annotating entries.
| Integration | Hook | Flag | Block |
|---|---|---|---|
| WordPress Comments | preprocess_comment | ✅ | ✅ |
| WordPress Registration | registration_errors | ✅ | ✅ |
| WooCommerce Checkout | woocommerce_after_checkout_validation | ✅ | ✅ |
| WooCommerce Registration | woocommerce_registration_errors | ✅ | ✅ |
| Contact Form 7 | wpcf7_spam | ✅ | ✅ |
| WPForms | wpforms_process_before_form_data | ✅ | ✅ |
| Gravity Forms | gform_validation | ✅ | ✅ |
| Elementor Pro Forms | elementor_pro/forms/validation | ✅ | ✅ |
| Ninja Forms | ninja_forms_submit_data | ❌ | ✅ |
| Fluent Forms | fluentform/before_insert_submission | ✅ | ✅ |
| Forminator | forminator_custom_form_submit_errors | ✅ | ✅ |
| Formidable Forms | frm_validate_entry | ✅ | ✅ |
| MC4WP (Mailchimp for WP) | mc4wp_form_errors | ❌ | ✅ |
Newsletter & CRM
Newsletter and CRM integrations support Block only — Flag is not available because these plugins have no native mechanism to hold or annotate a subscription for review.
| Integration | Hook | Flag | Block |
|---|---|---|---|
| Brevo (Sendinblue) | init | ❌ | ✅ |
| Email Subscribers | ig_es_validate_subscription | ❌ | ✅ |
| FluentCRM | fluentcrm_contact_created | ❌ | ✅ |
| Kit (ConvertKit) | init + rest_request_before_callbacks | ❌ | ✅ |
| MailerLite | wp_ajax_nopriv_mailerlite_subscribe_form | ❌ | ✅ |
| MailPoet | mailpoet_subscription_before_subscribe | ❌ | ✅ |
| Newsletter | newsletter_subscription | ❌ | ✅ |
Configuration
Admin UI
After activation, go to Opportify → Settings in the WordPress admin:
- General tab — Enter your API keys, enable/disable protection globally, toggle admin skip and logging options.
- Integrations tab — Enable each integration individually and set the action per risk level (Allow / Flag / Block).
Config File (DevOps / CI)
For version-controlled or automated environments (Bedrock, Trellis, etc.), create opportify-config.php in your WordPress root:
<?php
return [
// Required — plugin will not process submissions without valid keys
'private_key' => getenv('OPPORTIFY_PRIVATE_KEY'),
'public_key' => getenv('OPPORTIFY_PUBLIC_KEY'),
'enabled' => true,
'skip_admins' => true,
'log_enabled' => true,
'log_retention_days' => 30,
'integrations' => [
'wordpress' => ['enabled' => true, 'action_medium' => 'flag', 'action_high' => 'block', 'action_highest' => 'block'],
'woocommerce' => ['enabled' => true, 'action_medium' => 'flag', 'action_high' => 'block', 'action_highest' => 'block'],
'cf7' => ['enabled' => true, 'action_medium' => 'flag', 'action_high' => 'block', 'action_highest' => 'block'],
'wpforms' => ['enabled' => true, 'action_medium' => 'flag', 'action_high' => 'block', 'action_highest' => 'block'],
'gravity_forms'=> ['enabled' => true, 'action_medium' => 'flag', 'action_high' => 'block', 'action_highest' => 'block'],
// ... other integrations
],
];
When a config file is detected, the admin UI becomes read-only and displays a notice.
Risk Levels & Actions
The plugin uses a 5-level risk scale: Lowest, Low, Medium, High, Highest. For each integration, you configure what happens at each level:
| Action | Behavior |
|---|---|
| Allow | Submission proceeds normally; the analysis is logged to the plugin's internal reports but no risk metadata is written to the integration's native entry storage |
| Flag | Submission proceeds, risk metadata is stored for review |
| Block | The plugin rejects the submission locally with a configurable error message, based on your configured threshold |
How Flagging Works
When a submission is flagged, it proceeds normally but the plugin writes risk metadata using each integration's native storage:
| Integration | Storage | Meta Keys |
|---|---|---|
| WordPress Comments | comment_meta | _opportify_score, _opportify_level, _opportify_factors |
| WordPress Registration | user_meta | Same |
| WooCommerce Orders | Order meta | Same |
| Form plugins | Plugin entry meta | Same |
Flagged entries display a risk badge in their respective WP Admin list tables (Comments, Users, WooCommerce Orders).
Reports Dashboard
The plugin includes a built-in reports page (Opportify → Reports) with:
- Risk distribution charts — visual breakdown of submissions by risk level
- Submission log — searchable table with email/IP intelligence chips (deliverable status, connection type, country, blocklist)
- Site health checklist — verifies API connectivity, JS SDK loading, and integration status
- Full Details links — drill into any entry on app.opportify.ai for deeper analysis
Features
- Invisible detection — no CAPTCHA or user interaction required; legitimate users are never interrupted
- Per-integration control — different thresholds for comments vs checkout vs newsletters
- Skip admins — bypass checks for users with
manage_optionscapability during development - Automatic log retention — configurable WP-Cron cleanup (default 30 days)
- Cache-compatible — JS SDK registered via
wp_enqueue_scriptswith named handle - Auto-versioned JS SDK — fetches the latest version URL from the CDN manifest (
latest.json), cached as a WordPress transient with 2-hour TTL; falls back to the last cached URL if the manifest is unreachable - Multisite support — network-wide activation with per-site configuration
- Fully translated — ships with 10 locales: DE, ES, FR, IT, JA, NL, PL, PT-BR, RU, ZH-CN
Developer Hooks
The plugin exposes WordPress filters and actions so third-party code can extend or customize the fraud-analysis pipeline. All hooks fire during the analyze_and_act() lifecycle.
opportify_trusted_proxies (filter)
Declare the IP addresses of your reverse proxies (Cloudflare, load balancers, CDN edge nodes) so the plugin can safely read the real client IP from forwarding headers. Without this filter, only REMOTE_ADDR is used — which is the proxy's IP when you're behind one.
How it works:
- The plugin reads
$_SERVER['REMOTE_ADDR']. - If
REMOTE_ADDRexactly matches one of the IPs returned by this filter, the plugin trusts forwarding headers and checks them in order:CF-Connecting-IP→X-Forwarded-For(first IP) →X-Real-IP. - The first valid IP found in those headers becomes the client IP sent to the API.
- If
REMOTE_ADDRdoes not match any trusted proxy, forwarding headers are ignored entirely — preventing IP spoofing by attackers who set these headers on direct requests.
The filter uses strict equality matching. CIDR notation (e.g. 10.0.0.0/8) is not supported. You must list each proxy IP individually.
add_filter('opportify_trusted_proxies', function (): array {
return [
'203.0.113.10', // Your load balancer
'203.0.113.11', // Failover LB
];
});
| Parameter | Type | Description |
|---|---|---|
$proxies | string[] | Default empty array. Return an array of exact proxy IP addresses. |
opportify/fraud/form_data (filter)
Modify or enrich the form data array before it is sent to the Fraud Protection API. Use this to add custom fields, normalize values, or strip sensitive data.
add_filter('opportify/fraud/form_data', function (array $form_data, string $integration_key): array {
// Add a custom field for the API
$form_data['company'] = get_user_meta(get_current_user_id(), 'company', true);
return $form_data;
}, 10, 2);
| Parameter | Type | Description |
|---|---|---|
$form_data | array | Normalized form data (includes email, ip, and integration-specific fields). |
$integration_key | string | Integration identifier (e.g. wordpress, woocommerce, cf7). |
Return: array — the modified form data.
opportify/fraud/action (filter)
Escalate the action decision after risk evaluation. Third-party plugins can make the action stricter (allow → flag, allow → block, flag → block) but can never downgrade it (block → allow). The plugin enforces escalation-only semantics, so admin-configured protection cannot be bypassed by external code.
Precedence rules:
- The
$actionparameter you receive is already the result of the admin's risk-level settings (e.g. "block at high"). Your filter runs after that evaluation. - Returning a stricter action is honored:
allow→flag,allow→block,flag→block. - Returning a less strict action is silently ignored — the original action is preserved. For example, if admin settings produce
block, returningalloworflaghas no effect. - Returning an invalid value (anything other than
allow,flag, orblock) falls back to the original action.
add_filter('opportify/fraud/action', function (string $action, ?object $result, array $form_data, string $integration_key): string {
// Block all submissions from disposable email providers
if (str_ends_with($form_data['email'] ?? '', '@tempmail.com')) {
return 'block';
}
return $action;
}, 10, 4);
| Parameter | Type | Description |
|---|---|---|
$action | string | The computed action: allow, flag, or block. |
$result | object|null | Raw API result object (contains score, level, factors, sources). |
$form_data | array | The form data that was analyzed. |
$integration_key | string | Integration identifier. |
Return: string — the action to take. Downgrades are silently ignored.
opportify/fraud/analyzed (action)
Fires after the fraud analysis completes and the action has been determined. Use this for logging to external systems, triggering notifications, or syncing with CRMs.
add_action('opportify/fraud/analyzed', function (?string $email, ?object $result, string $integration_key): void {
// Send high-risk submissions to a Slack webhook
if (($result->level ?? '') === 'highest') {
wp_remote_post('https://hooks.slack.com/...', [
'body' => wp_json_encode(['text' => "🚨 High-risk submission from {$email} ({$integration_key})"]),
]);
}
}, 10, 3);
| Parameter | Type | Description |
|---|---|---|
$email | string|null | The email address from the submission. |
$result | object|null | Raw API result object. |
$integration_key | string | Integration identifier. |
opportify/fraud/block_message (filter)
Customize the user-facing message shown when a submission is blocked. Use this to personalize messages per integration or locale.
add_filter('opportify/fraud/block_message', function (string $message, string $integration_key, array $form_data): string {
if ($integration_key === 'woocommerce') {
return __('Your order could not be processed. Please contact support.', 'my-plugin');
}
return $message;
}, 10, 3);
| Parameter | Type | Description |
|---|---|---|
$message | string | The configured block message from settings. |
$integration_key | string | Integration identifier. |
$form_data | array | The form data that triggered the block. |
Return: string — the message to display to the user.
Hook Execution Order
During each form submission the hooks fire in this order:
opportify_trusted_proxies— resolves the client IPopportify/fraud/form_data— prepares and enriches data- API call to Fraud Protection
opportify/fraud/action— post-analysis action escalationopportify/fraud/analyzed— notification after decision is finalopportify/fraud/block_message— fires only when the final action isblock, afteranalyze_and_act()has returned; it is called by the integration to retrieve the error message before rejecting the submission
External Services
| Service | URL | Purpose |
|---|---|---|
| Fraud Protection API | https://api.opportify.ai/intel/v1/fraud/analyze | Server-side risk analysis (Private Key via x-opportify-token header) |
| JS SDK CDN | https://cdn.opportify.ai/f/v{version}.min.js | Client-side behavioral telemetry (Public Key via data-opportify-key attribute) |
| JS SDK manifest | https://cdn.opportify.ai/f/latest.json | Resolves the latest JS SDK version |
See Privacy Policy and Terms of Service.