Click-fraud protection is worth evaluating when it solves a recurring problem and improves a business outcome after its full cost. A dashboard’s blocked-click value does not establish that result. Compare verified actions, billed costs, legitimate-customer effects and realized outcomes.
This guide is published by AdProtektor. Apply the same test to us, a competing provider or a manual process. The useful question is what changes for your business, compared with the protection and workflow you already have.
1. Choose the job before the subscription
| Job | Starting option | Evidence to evaluate |
|---|---|---|
| Understand native invalid-traffic filtering | Google Ads reports and billing records | Filtered interactions and actual adjustments |
| Maintain a small known list | Reviewed manual exclusions | Source evidence, correct scope, capacity and maintenance time |
| Investigate recurring suspicious visits | Visitor evidence and a review workflow | Useful reasons, legitimate exceptions and time spent investigating |
| Automate eligible enforcement | A configured protection service | Connection, supported action, synchronization and effect on real customers |
| Stop unreliable form events driving bidding | Acceptance, qualification and conversion-delivery checks | Received/qualified outcomes and the actual campaign goals |
The native filtering, manual exclusions and AdProtektor comparison explains these scopes. Fix a broken form or duplicate conversion path before buying a tool to solve the wrong problem.
2. Separate flags, actions and money
- Observation: a visit, request pattern or network label was recorded.
- Decision: a rule or provider classified it.
- Action: a website rule or eligible platform exclusion actually took effect.
- Billing: the platform’s charge or verified adjustment changed.
- Business outcome: customer contribution, qualified demand or review time changed.
Keep a record for each stage. A blocked visit multiplied by an average CPC is a hypothetical value, not a verified reduction in your bill. Google may already have filtered the interaction, and the campaign may spend available budget on other traffic.
Google’s invalid-traffic documentation distinguishes filtering before billing from eligible later credits. It also explains why third-party flags can include traffic Google already filtered. Checked 3 November 2026.
Credits must be mapped to their original charge period. If the cost number already includes those credits, do not subtract them again. Keep pending investigations and estimated recoveries out of realized savings.
3. Design a comparison that isolates the change
Define the eligible population, assignment unit, outcome, cost allocation and follow-up window before starting. Keep unrelated bidding, budget, creative and landing-page changes steady where possible. Record unavoidable changes.
Where the platform and protection setup support it, use a planned comparison with a defensible assignment method. A good week after installation is not enough: seasonality, conversion delay and traffic mix can move the outcome too.
Google’s experiment guidance recommends a clear hypothesis, selected success metrics and one changed variable. Its experiment methodology explains assignment and uncertainty. These references describe campaign experiments, not a built-in randomized protection test for every vendor.
An account-wide rule can affect both arms
Google account-level IP exclusions apply across campaigns, and campaign/account lists are combined. If protection writes to that shared list, a control campaign can receive the same exclusion as the treatment. A campaign split alone then fails to isolate protection.
The shared-list boundary comes from Google’s IP-exclusion scope. The test-contamination implication follows from that scope.
Check site-wide rules, shared audiences and visitor identity across campaigns too. Confirm that the proposed control really stays outside the tested treatment. AdProtektor’s presence in this guide does not imply it offers a native randomized protection holdout.
Preserve existing safeguards and legitimate-customer exceptions. If you cannot isolate the change, use the review to describe observed costs and workflow effects; do not label a before/after difference as incremental savings. Unequal arm sizes also need an appropriate estimator, not an unadjusted difference of totals.
Predefine duration/sample requirements, conversion and qualification follow-up, guardrails and a decision rule. Do not stop at the first favorable day. Thin data can leave the decision inconclusive.
4. Run a cost comparison with explicit inputs
Use customer contribution after product, fulfilment and refund costs, but before acquisition costs. Then subtract net ad cost, allocated tool fees and implementation/review costs. Do not subtract the same expense in both the contribution input and the acquisition total.
net_ad_cost = gross_ad_charges - verified_credits
all_in_acquisition_cost = net_ad_cost + tool_fee + review_cost
net_contribution = contribution_before_acquisition - all_in_acquisition_cost
observed_net_difference = protected_net_contribution - control_net_contributionreview_cost includes the setup and ongoing review costs you choose to allocate. Use the same period, currency, allocation policy and outcome maturity for both arms. The demo assumes a two-decimal reporting currency and does not convert currencies.
Download both files into one folder and run the command with Python 3.9 or later. It reads local CSV, validates every comparison before printing JSON, contacts no service and writes no report files:
python3 protection-value-demo.py protection-value-example.csvInspect all synthetic inputs
scenario,arm,currency,closed_customers,contribution_before_acquisition,gross_ad_charges,verified_credits,tool_fee,review_cost,flagged_spend_claim
observed_gain,control,USD,10,1600.00,1020.00,20.00,0.00,50.00,0.00
observed_gain,protected,USD,12,1800.00,1030.00,30.00,40.00,80.00,250.00
unchanged_outcome,control,USD,10,1600.00,1020.00,20.00,0.00,50.00,0.00
unchanged_outcome,protected,USD,10,1600.00,1030.00,30.00,40.00,80.00,250.00
no_closed_customers,control,USD,0,0.00,400.00,0.00,0.00,20.00,0.00
no_closed_customers,protected,USD,0,0.00,400.00,0.00,40.00,20.00,250.00Inspect the complete local calculation
#!/usr/bin/env python3
"""Local arithmetic example. No network requests, account access or output files.
Usage: python3 protection-value-demo.py protection-value-example.csv
Inputs must be allocated to a comparable scope/period before this program runs.
The script does not establish treatment assignment or causal savings.
"""
import csv
import json
import io
import re
import sys
from decimal import Decimal, ROUND_HALF_UP
from pathlib import Path
FIELDS = ['scenario', 'arm', 'currency', 'closed_customers',
'contribution_before_acquisition', 'gross_ad_charges',
'verified_credits', 'tool_fee', 'review_cost', 'flagged_spend_claim']
CENT = Decimal('0.01')
LIMIT = Decimal('1000000000000')
def money(value, field):
if not re.fullmatch(r'-?[0-9]+(?:\.[0-9]{1,2})?', value or ''):
raise ValueError(field + ': use an unformatted decimal with at most two places')
number = Decimal(value)
if abs(number) > LIMIT:
raise ValueError(field + ': exceeds this example\'s amount limit')
if field != 'contribution_before_acquisition' and number < 0:
raise ValueError(field + ': use a non-negative amount')
return number
def show(value):
return str(value.quantize(CENT, rounding=ROUND_HALF_UP))
def evaluate(text):
reader = csv.DictReader(io.StringIO(text), strict=True)
if reader.fieldnames != FIELDS:
raise ValueError('CSV headers/order do not match the example')
groups = {}
for line, row in enumerate(reader, 2):
if None in row or any(value is None for value in row.values()):
raise ValueError('row %s: missing or extra fields' % line)
row = {key: value.strip() for key, value in row.items()}
scenario, arm, currency = row['scenario'], row['arm'], row['currency']
if not re.fullmatch(r'[a-z0-9_]{1,64}', scenario):
raise ValueError('row %s: invalid scenario name' % line)
if arm not in ('control', 'protected') or not re.fullmatch(r'[A-Z]{3}', currency):
raise ValueError('row %s: invalid arm or currency' % line)
if not re.fullmatch(r'[0-9]+', row['closed_customers']):
raise ValueError('row %s: closed_customers must be a non-negative integer' % line)
customers = int(row['closed_customers'])
amounts = {field: money(row[field], field) for field in FIELDS[4:]}
if amounts['verified_credits'] > amounts['gross_ad_charges']:
raise ValueError('row %s: credits must belong to the selected gross charges; do not use a carried balance' % line)
group = groups.setdefault(scenario, {})
if arm in group:
raise ValueError('row %s: duplicate scenario/arm' % line)
net_ad = amounts['gross_ad_charges'] - amounts['verified_credits']
acquisition = net_ad + amounts['tool_fee'] + amounts['review_cost']
net = amounts['contribution_before_acquisition'] - acquisition
# flagged_spend_claim is validated but never counted as savings.
group[arm] = {'currency': currency, 'net': net,
'report': {'net_ad_cost': show(net_ad),
'all_in_acquisition_cost': show(acquisition),
'net_contribution': show(net),
'cost_per_closed_customer': show(acquisition / customers) if customers else None}}
if not groups:
raise ValueError('CSV has no comparison rows')
output = []
for scenario, group in sorted(groups.items()):
if set(group) != {'control', 'protected'}:
raise ValueError(scenario + ': include exactly one control and one protected row')
if group['control']['currency'] != group['protected']['currency']:
raise ValueError(scenario + ': comparison currencies must match')
output.append({'scenario': scenario, 'currency': group['control']['currency'],
'control': group['control']['report'],
'protected': group['protected']['report'],
'observed_net_difference': show(group['protected']['net'] - group['control']['net'])})
return output
def main(argv):
if len(argv) != 1:
raise ValueError('usage: python3 protection-value-demo.py protection-value-example.csv')
# Parse and validate every row before emitting any report.
output = evaluate(Path(argv[0]).read_text(encoding='utf-8'))
print(json.dumps(output, indent=2))
if __name__ == '__main__':
try:
main(sys.argv[1:])
except (ValueError, OSError, csv.Error) as error:
print('protection-value-demo: ' + str(error), file=sys.stderr)
sys.exit(1)All amounts, including the $40 tool fee and $250 flagged-spend claim, are synthetic inputs. Here is the resulting net contribution in USD:
| Scenario | Control | Protected | Observed difference |
|---|---|---|---|
observed_gain | 550.00 | 680.00 | 130.00 |
unchanged_outcome | 550.00 | 480.00 | -70.00 |
no_closed_customers | -420.00 | -460.00 | -40.00 |
In observed_gain, both arms have net ad cost of $1,000; the larger customer contribution produces a $130 difference after costs. In unchanged_outcome, the same customer contribution and ad cost leave the protected arm $70 lower because of its extra costs. The $250 flag estimate adds nothing to either calculation.
In no_closed_customers, cost per closed customer is JSON null, not zero. Negative contribution is allowed. Credits must belong to the selected gross charges; a carried account balance is not that input. Pending outcomes and uncertain credits need a separate sensitivity review.
Arithmetic does not establish a treatment effect
The script checks the cost definitions. It does not validate assignment, normalize unequal exposure, estimate uncertainty or attribute a customer to protection. Establish a comparable, uncontaminated evaluation before interpreting the difference as an effect.
5. Validate the outcome signal before judging the tool
A protection trial cannot be judged fairly if “success” mixes page views, form attempts, accepted enquiries and customers. Review duplicate paths and the actions selected by the campaign. Qualification still happens in your business workflow.
Runs in this browser. Your action names and settings stay here.
Check campaign goals to confirm bidding eligibility. Custom goals can include secondary actions. Match transaction or lead IDs to verify repeated events.
The audit reviews exported settings locally; it does not read or change an account. Follow the read-only export script and instructions, then inspect actual campaign/custom goals. The conversion-signal diagnostic explains that second step.
6. Set the decision and follow-up
Download the protection-value evaluation worksheet. It records assignment, shared-rule spillover, costs, outcome delay, exceptions and the next decision.
Open the complete worksheet
CLICK-FRAUD PROTECTION — VALUE EVALUATION
One problem the protection must solve:
Primary business outcome and definition:
Measurement, lead acceptance and qualification already verified:
SCOPE AND ASSIGNMENT
Accounts / campaigns / sites / channels in scope:
Eligibility and assignment unit:
Control condition and protected condition:
How treatment stays out of the control:
Account-level exclusion lists affecting both arms:
Site-wide rules, shared audiences and cross-campaign identity effects:
If isolation is unavailable, comparison limitations to report:
Other changes held steady / unavoidable changes recorded:
Start / end / account timezone:
Conversion and business-qualification follow-up cutoff:
Predefined sample/duration, stop conditions and decision rule:
Owner, legitimate-visitor exception path and rollback:
EVIDENCE (keep each stage separate)
Observed visit and review reason:
Protection decision:
Website action, if applicable:
Platform exclusion request / synchronization status / scope:
Native invalid-traffic reporting:
Verified invoice adjustment mapped to the original charge period:
Accepted / qualified / closed business outcomes:
Legitimate customers affected and resolution:
COST INPUTS PER ARM, FOR THE SAME ALLOCATED SCOPE
Currency and FX policy if needed (the demo does not convert currency):
Contribution from realized customers after product/fulfilment/refund costs,
but before ads, tool fees and review costs:
Gross ad charges:
Verified credits belonging to those selected charges:
Net ad cost (gross minus verified credits; do not subtract credits again):
Tool/license fee, allocated under a rule chosen before the comparison:
Implementation and review time cost, allocated consistently:
Unresolved refunds / sales / credits and sensitivity range:
Flagged-spend estimate (record separately; not booked savings):
DECISION
Observed net contribution for control / protected:
Observed difference, with uncertainty and contamination limits:
Evidence supporting causal interpretation, if any:
Enough evidence to continue / revise / stop / remain inconclusive:
Next review date and owner:
Do not paste customer records into shared notes.
A positive arithmetic difference alone is not an experiment result.- Continue: the measured job is useful, protection behaves as configured, legitimate-customer effects are acceptable and the evaluation supports its full cost.
- Revise: reasons, scope, goals or exception handling need a specific correction and another bounded review.
- Stop: the tool adds cost or friction without supporting the required outcome, or cannot provide the action/evidence your workflow needs.
- Remain inconclusive: assignment, contamination, unresolved business outcomes or volume prevent a reliable decision.
Inspect identity promises with the IP and browser-identity evaluation. Then compare published plans and trial conditions for the scope you actually need.
Evaluate AdProtektor against the same standard
AdProtektor adds evidence about observed visits and configurable protection. Eligible Google Ads exclusion updates need an active connection, permissions, supported scope and successful synchronization. Website enforcement and ConversionOS event handling are separate configured steps. None establishes a refund for the click that first revealed a source.
Start a free AdProtektor trial to inspect observed visits and configured decisions, using the worksheet to define your review before interpreting the results. The traffic-audit checklist is a starting point for the evidence.
When evaluating a provider, use the tracking and protection comparison to distinguish event delivery, website enforcement, ad exclusions and the evidence each control should produce.
Already using website security? The Cloudflare and ad-protection buyer guide separates challenge responses, legitimate customer completion, applied ad exclusions and billing evidence.