Rapls Copy Notice Pro Manual
Rapls Copy Notice Pro is an add-on for the free Rapls Copy Notice plugin. Working from the copies the free plugin records, it adds statistics, chat and webhook notifications, routing rules, a burst alert, a search for reposts of your text, and CSV export.
Detection, the log, email notifications and how long records are kept stay on the free plugin’s own tabs (Log / Notifications / Detection / Privacy / Visitors). For those, see the free plugin manual. Pro doesn’t block copying either.
01Getting started
Requirements
| Item | Requirement |
|---|---|
| Free Rapls Copy Notice | 1.3.19 or later, installed and active (required) |
| WordPress | 6.3 or later |
| PHP | 8.2 or later |
| Outbound HTTPS | Used to activate the license, check it daily and fetch updates. When you switch on a channel or the repost search, requests also go to that service |
| Multisite | Needs the 5-site license (details) |
- Free plugin missing or inactive:
Rapls Copy Notice Pro needs the Rapls Copy Notice plugin to be installed and active. - Free plugin older than 1.3.19:
Rapls Copy Notice Pro needs Rapls Copy Notice 1.3.19 or later. Please update Rapls Copy Notice.
Installation
- Install and activate the free Rapls Copy Notice (1.3.19 or later) from WordPress.org.
- Buy Pro on the product page. Your license key arrives by email.
- On the download page, enter the email address you bought with and your license key to get
rapls-copy-notice-pro.zip. - Go to Plugins → Add New Plugin → Upload Plugin, upload the ZIP and activate it. On multisite, upload it under Network Admin → Plugins and press Network Activate.
Once active, Tools → Rapls Copy Notice gains six tabs: Statistics, Channels, Rules, Reposts, Export and License. The free plugin’s “Pro features” tab goes away.
Activating the license
License keys look like RCNP-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX. Lower case is fine; the key is sent in upper case.
- Open Tools → Rapls Copy Notice → License. The License link in Pro’s row on the Plugins screen goes there too.
- Enter the address you bought with in Email and your key in License key.
- Press Activate license. You’re done when Status shows Active, followed by your email, the masked key (only the first and last five characters shown) and the Type.

Messages you may see when activating:
| Message | Meaning and what to do |
|---|---|
| License activated. (or a message from the server) | Done. |
| Please enter both the email address and the license key. | One is empty, or the email isn’t a valid address. |
| Could not connect to the license server. | Your server can’t make outbound HTTPS requests. Check your host’s firewall or outbound restrictions. |
| The license server returned an unexpected response. / The license server returned an invalid response. | A firewall, proxy or WAF on the way is probably answering instead of the license server. If it persists, contact us with the message. |
| Activation failed. (or a reason from the server) | The email and key don’t match, the site limit is reached, or the key was revoked. |
| A multisite network needs the 5-site license. This key is for 1 site and was not activated here. | You entered a 1-site key on a network. The seat the server had taken was released straight away. Use a 5-site key. |
The key and email are stored in the database (not autoloaded) and sent to the license server only in HTTPS request headers (X-RCN-License-Key / X-RCN-License-Email), never in a URL. Redirects aren’t followed, so the headers can’t be passed on to another server.
When Pro stops, and when it doesn’t
The license is a one-time purchase and doesn’t expire. After activation it is checked with the server once a day (the first check about a day after activating). Each check sends the key, the email and the site’s address.
| Situation | Pro features |
|---|---|
| The server says the license is valid | Run |
| The server can’t be reached (outage, firewall, outbound restrictions) | Keep running, however long it lasts |
| Something other than the server (a WAF or proxy) answers without a valid/invalid verdict | Treated like an outage; keep running |
| The server explicitly says the license is no longer valid (refund, revoked key, or this site’s address holds no seat) | Stop |
| No key entered, or released with Deactivate on this site | Stop |
Nothing is deleted. The log, Pro’s settings, your rules and found pages stay, and the free plugin carries on as usual. Activate again and everything resumes with the same settings.
Deactivating and moving sites
The 1-site license activates on one site, the 5-site license on up to five. Deactivate on this site on the License tab frees the seat on the server and removes the key and email stored on this site. There’s no confirmation step. If the server can’t be reached, the site’s copy is still removed but the seat may not be freed; contact us if that happens.
- Staging and cloned sites: copying the database doesn’t give the copy a seat, so the next check stops Pro there. To use Pro on the copy, activate it on that site (it uses a seat).
- Deleting Pro doesn’t free the seat. Deactivate first.
Multisite
- A network needs the 5-site license. It then covers every site in the network, however many there are. The license is registered with the network’s main address.
- Network-activate both the free plugin and Pro. The license screen is in Network Admin, and it only appears there when Pro is network-activated.
- The license is managed by super admins (
manage_network_options) under Network Admin → Settings → Rapls Copy Notice Pro. The button there reads Deactivate on this network. - Each site’s License tab shows “License status: Active for this network” or “Not active”. Super admins get a Manage the license in Network Admin link; other administrators see “The license is managed by the network administrator.”
- The log and the channel, rule and repost settings are separate per site. Each site’s administrators set up their own.
- If a single site activated with a 1-site license is later turned into a network, Pro stops.
Where the screens are
| Screen | Where | Who |
|---|---|---|
| Statistics / Channels / Rules / Reposts / Export | Tabs on Tools → Rapls Copy Notice | Administrators (manage_options) |
| License (single site) | Tools → Rapls Copy Notice → License | Administrators |
| License and per-site counts (multisite) | Network Admin → Settings → Rapls Copy Notice Pro | Super admins |
| Free plugin settings (log, email, exclusions, retention) | Log / Notifications / Detection / Privacy / Visitors tabs on the same screen | Administrators |
| Updates | Dashboard → Updates, Plugins | Users who can update plugins |
02Statistics
Copies per day from the free plugin’s log, set against the previous period. It only reads the log and changes nothing.

Periods and the previous period
- Pick Last 7 days, Last 30 days or Last 90 days with the links at the top. The default is 30 days.
- A period is the N days ending at the end of today in the site’s time zone (Settings → General). The previous period is the same number of days immediately before it.
- The top line reads “
N copies in this period” with the change against the previous period, for example(+12.5% vs previous period: 8). When the previous period had none, it shows(previous period: 0)instead of a percentage. - The chart shows copies per day: a solid line for This period and a dashed line for Previous period. Chart.js 4.5.1 is bundled with the plugin; nothing loads from a CDN.
By post and by paragraph
Most copied posts lists the top 20 posts in the period.
| Column | Contents |
|---|---|
| Post | Post title and ID |
| This period / Previous | Copies in this period and in the previous one |
| Change | Percentage change; new when the previous period had none and this one has some |
| Details | Paragraphs opens the post’s paragraph table. Log opens the free plugin’s Log tab filtered to that post |
Paragraphs adds Most copied paragraphs: post title above the list: the top 20 paragraphs, each shown by the first 120 characters of the text most recently copied from it (hover for the full text). Its Log link opens the log filtered to that post and paragraph. Back to all posts returns to the list.

Paragraphs are told apart by a fingerprint (paragraph_hash) the free plugin computes in the visitor’s browser. These copies have none and stay out of the paragraph table; their number is shown under it:
- copies recorded before free version 1.2;
- copies on a page not served over HTTPS (the browser won’t compute the fingerprint there);
- copies from outside a paragraph, such as a heading or a table.
03Channels
Each notification the free plugin sends also goes to Slack, Discord, Chatwork or your own webhook, at the same moment as the email. The timing is whatever you chose under When to send on the free plugin’s Notifications tab: One summary email per hour or One email per copy, right away.

Fields
Each channel has a Send notifications here checkbox. All are off by default.
| Channel | Field | Accepted format |
|---|---|---|
| Slack | Incoming webhook URL | https://hooks.slack.com/services/… (/workflows/ and /triggers/ also accepted) |
| Discord | Webhook URL | https://discord.com/api/webhooks/digits/token (ptb., canary. and discordapp.com also accepted) |
| Chatwork | API token | 20–64 letters and digits |
| Room ID | Digits only (e.g. 123456789) | |
| Webhook | URL (HTTPS) | HTTPS to a public host, up to 2,000 characters. localhost and private (internal) addresses are refused |
| Signing secret (optional, 16+ characters) | 16–128 printable ASCII characters, no spaces. Leave empty for unsigned requests |
- URLs, tokens and the signing secret are never shown in full once saved. Under the field you’ll see a hint such as “
Saved: hooks.slack.com …a1b2. Leave empty to keep it.” Saving with the field empty keeps the stored value; tick Remove and save to clear it. - A value in the wrong format isn’t saved and the previous one stays. You’ll see “Settings saved, but some values were not in the expected format and were left unchanged. …”
- A channel without its URL or token is switched back off when you save, even if you ticked it.
Visitor data sent chooses what Slack, Discord, Chatwork and the webhook receive about each copy. Everything is ticked by default.
| Item | When unticked |
|---|---|
| Copied text | Chat messages leave out the copied-text block. The webhook’s copied_text is an empty string (text_length is still sent) |
| IP address (as stored) | No IP is sent. The webhook’s ip is empty |
| User agent | No browser string is sent. The webhook’s user_agent is empty |
| Referrer host | No referrer is sent. The webhook’s referrer_host is empty |
- The post, its URL and the time are always sent; a notification means nothing without them.
- Email isn’t affected; the free plugin decides what the email contains.
- The privacy policy text the free plugin suggests (Settings → Privacy) lists only the ticked items as what is sent.
Getting a Slack webhook URL
- On Slack’s API site (
api.slack.com/apps), create a new app for your workspace (“From scratch”, then name it and pick the workspace). - In the app’s settings, open Incoming Webhooks and switch it on.
- Press Add New Webhook, choose the channel to post to, and allow it.
- Copy the
https://hooks.slack.com/services/…URL shown, paste it into Incoming webhook URL on the Channels tab, and save.
Some workspaces need an admin’s approval to add an app.
Getting a Discord webhook URL
- In the server you want to post to, open Server Settings → Integrations → Webhooks (you need permission to manage webhooks).
- Create a New Webhook, name it and choose the channel.
- Press Copy Webhook URL, paste it into Webhook URL on the Channels tab, and save.
Getting a Chatwork API token and room ID
- From the account menu at the top right of Chatwork, open Integrations (Service integration) and issue or show your token under API Token. On organisation accounts, API use may need an admin’s approval.
- Paste the token into API token on the Channels tab.
- Open the chat you want to post to. The address bar ends with
#!rid123456789; enter the digits (123456789) in Room ID and save.
Messages are posted under the name of the account that issued the token, and show as unread for that account too. A separate account for notifications makes them easier to tell apart.
Test messages
Below the fields, Send a test message has Slack, Discord, Chatwork and Webhook buttons. Each sends one sample with made-up data using the saved settings, even if that channel is switched off. Values you’ve typed but not saved aren’t used, so save first.
- The sample text deliberately contains HTML tags, a Chatwork tag,
@everyoneand. If they all appear as plain text, everything is working. - Success: "Test message sent."
- Failure: "The test message could not be delivered. Check the URL or token, and that the service accepts requests from this server." Check the URL, token and room ID, and that your server can make outbound requests.
What arrives
The heading is "[Site name] N copies detected" ("copy" for one). Up to 10 copies are listed in full per message; the rest are summed up as "…and N more in the log." Each entry has the date, the post title and URL, the copied text (first 200 characters), the IP address and the user agent (Slack also shows the referring host). Discord caps message length, so it lists as many as fit.
· Mozilla/5.0 (iPhone; …) · from www.google.com 10/9/2026 12:40 pm — Summer garden jobs https://example.com/garden/
Put fertiliser a little away from the stem.
IP 198.51.100.0 · Mozilla/5.0 (Windows NT 10.0; …)`- IP addresses arrive as the free plugin stored them, shortened by default.
- With “right away” notifications, the free plugin’s Instant email limit (per hour) applies to channels too. Copies over it go into the next hourly summary.
- A notification counts as sent once the email or any one channel accepts it. A channel that failed then gets its own retries. If everything fails, it isn’t marked as sent and the whole notification goes out again with the free plugin’s hourly summary.
- Each request gives up after 5 seconds and doesn’t follow redirects.
How visitor data is handled
Copied text, IP, user agent and referrer come from visitors’ browsers; titles and snippets of pages found by the repost search come from third parties. Each channel neutralises them for its own format before sending:
| Channel | Handling |
|---|---|
| Slack | &, < and > are sent as entities, so text can’t mention @channel or a user, or form a link. Untrusted values are shown as code |
| Discord | Untrusted values are in code blocks or code spans, and mentions are switched off for every message |
| Chatwork | [ and ] in untrusted text become full-width [ ], so they can’t form [To:], [info] or other tags |
| Webhook | Values are sent as recorded, in JSON. Treat them as untrusted on the receiving side |
| Plain text only; the subject is the site name and fixed wording |
Delivery history and retries
At the bottom of the Channels tab, Delivery history lists up to 50 of the copy notifications sent to each channel in the last 30 days, newest first. Burst and repost alerts aren’t listed.
| Column | Contents |
|---|---|
| Time | When it was first sent |
| Channel | Slack, Discord, Chatwork or Webhook |
| Copies | How many copies the notification covered |
| Status | Sent (green), Failed, next try date (an automatic retry is scheduled) or Failed (automatic retries are over). Failures show the reason underneath, e.g. “The service answered with HTTP 500.” |
| Attempts | The first send plus automatic retries |
| Actions | Send again now on failed ones. It sends at once and says “Sent again.” or “Sending again failed. …” |
Automatic retries are for notifications that reached email or another channel but not this one. That channel alone is tried again after 15 minutes, 1 hour, 3, 6 and 12 hours. A notification that reached nowhere isn’t retried here: the free plugin sends the whole notification again with the next summary, and retrying it here too would send it twice.
- A retry rebuilds the message from the log at that time, with the current Visitor data sent choice. Copies deleted from the log are left out; if none are left it stops with “The copies in this notification are no longer in the log.”
- A webhook retry carries the same
X-RCN-Deliveryas the first send, so the receiver can drop duplicates. - Retries run on WP-Cron, so on a quiet site they can be later than scheduled.
- History is kept for 30 days (entries still waiting for a retry stay).
Webhook (JSON and signature)
Sends each notification as a JSON POST to your own system or automation service. The receiver must answer with a 2xx within 5 seconds; anything else counts as a failure.
| Header | Value |
|---|---|
Content-Type | application/json; charset=utf-8 |
X-RCN-Event | copies (copy notification), test (test message), burst (burst alert), repost (repost alert) |
X-RCN-Delivery | An ID (UUID) per notification. It stays the same when the notification is sent again, so receivers can drop duplicates |
X-RCN-Timestamp | When this request was sent (Unix time, seconds). New on every retry |
X-RCN-Signature | Only when a Signing secret is set: sha256= followed by the HMAC-SHA256 of the X-RCN-Timestamp value, a . (dot) and the body, in lower-case hex. Up to Pro 1.1.3 it covered the body only |
Body of a copy notification (up to 100 items; copied_text in full):
{
"event": "copies",
"context": "digest",
"site": "https://example.com/",
"total": 1,
"items": [
{
"id": 1234,
"created_at": "2026-10-09T03:15:00+00:00",
"post_id": 42,
"post_title": "Summer garden jobs",
"post_url": "https://example.com/garden/",
"copied_text": "Water in the cool of the morning, slowly, at the base of the plant.",
"text_length": 68,
"ip": "192.0.2.0",
"user_agent": "Mozilla/5.0 (iPhone; …)",
"referrer_host": "www.google.com",
"paragraph_hash": "(40 hex digits, or an empty string)"
}
]
} contextisinstant(right away),digest(hourly summary) ortest.created_atis in UTC.- In a test message,
eventandcontextaretest,idandpost_idare 0, and the post title and URL are empty. - Burst and repost alerts have a different shape:
{"event": "burst", "context": "alert", "site": …, "heading": …, "data": {"post_id": 42, "copies": 12, "minutes": 10}}. For reposts,"data": {"matches": [{"post_id", "post_url", "url", "title"}, …]}. - On the wire,
/is sent as\/and non-ASCII text as\uXXXX. Parsed as JSON, the values are the same. - Items unticked under Visitor data sent keep their keys with an empty string, so the JSON’s shape doesn’t change.
Verifying the signature in PHP. Compute it over the body exactly as received, not over JSON you’ve decoded and re-encoded. Rejecting timestamps more than five minutes old means a captured request can’t be replayed later.
$body = file_get_contents( 'php://input' );
$secret = 'the Signing secret from the Channels tab';
$timestamp = isset( $_SERVER['HTTP_X_RCN_TIMESTAMP'] ) ? $_SERVER['HTTP_X_RCN_TIMESTAMP'] : '';
$given = isset( $_SERVER['HTTP_X_RCN_SIGNATURE'] ) ? $_SERVER['HTTP_X_RCN_SIGNATURE'] : '';
$expected = 'sha256=' . hash_hmac( 'sha256', $timestamp . '.' . $body, $secret );
if ( ! ctype_digit( $timestamp ) || abs( time() - (int) $timestamp ) > 300 || ! hash_equals( $expected, $given ) ) {
http_response_code( 401 );
exit;
}
// If this X-RCN-Delivery was seen before, answer 2xx without processing it again.
$data = json_decode( $body, true );
// Values in $data['items'] came from visitors. Escape them wherever you display them.
http_response_code( 204 ); In Node.js:
const crypto = require('crypto');
// rawBody is the body exactly as received (a Buffer)
const ts = req.get('X-RCN-Timestamp') || '';
const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(ts + '.').update(rawBody).digest('hex');
const given = req.get('X-RCN-Signature') || '';
const fresh = /^\d+$/.test(ts) && Math.abs(Date.now() / 1000 - Number(ts)) <= 300;
const ok = fresh && given.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected)); localhost and private IP addresses are refused both when you save and on every send. Redirects aren’t followed. 04Rules
Decide which copies go where, by post, category and length of the copied text. Destinations are Email (the free plugin’s Send notifications to address), Slack, Discord, Chatwork and Webhook.

How routing is decided
- With no rule switched on, every copy goes to the email and to every channel that’s on, as before.
- Once at least one rule is on, a copy goes to the destinations of every rule it matches (once each, even if several rules name the same one).
- Copies that match no rule follow the setting below.
- Choosing Slack (or another channel) in a rule does nothing unless that channel is switched on in the Channels tab. Such channels are labelled “(not switched on)” in the choices.
- Rules only filter notifications. Every copy is still logged and counted in Statistics.
The Routing rules list has the columns Rule (name, with “(off)” when switched off), Applies to (a summary), Send to (“Nowhere (drop)” when none is chosen) and Actions (Edit / Delete). Delete doesn’t ask for confirmation.
Rule fields
Add one with Add a rule. Up to 20 rules.
| Field | Default | Description |
|---|---|---|
| Name and On | empty / on | Up to 80 characters (shown as #number when empty). Untick On to keep the rule without it taking effect |
| Posts | empty | Post IDs separated by commas (up to 200) |
| Categories | none | Tick post categories (up to 200 are listed) |
| Length | 0 | “N characters or more“. Matches only copies at least this long. 0 matches any length |
| Send to | none | Any of Email / Slack / Discord / Chatwork / Webhook. Choose none to drop matching copies from notifications (they’re still logged) |
A copy matches when its post is one of the Posts or in one of the Categories, and it’s at least Length characters long. With both Posts and Categories empty, a rule matches every post.
Example: members-only posts also to Slack, everything else by email only
Rule 1: Categories = “Members only”, Send to = Slack. Rule 2: Posts and Categories empty, Send to = Email. Copies from members-only posts match both rules, so they go to Slack and email. Other copies match only rule 2 and go to email. Because rule 2 matches every post, Copies matching no rule has no effect here. Timing (right away or hourly) is one free plugin setting for the whole site.
Copies matching no rule
Set under Other settings → Copies matching no rule. It only applies once at least one rule is on.
- Send to every channel (default): the email and every channel that’s on.
- Do not notify: no notification. The copy is still logged.
Try a copy
Under the rule list, Try a copy takes a post (the latest 100) and Characters copied; Show where it goes then shows where such a copy would be sent under the current rules. Nothing is recorded or sent.
- It reads like “Matching rules: rule name.” and “Sent to: Email, Slack.” With no rule matching: “No rule matches, so the setting for copies matching no rule applies.” With no rule on: “No rule is on, so every copy goes to email and every switched-on channel.”
- When nothing would be sent: “Sent nowhere: the copy is recorded in the log only.”
Switched-off channels: when a rule, or the burst or repost alert settings, choose a channel that is off on the Channels tab, you’ll see “Nothing is sent to Slack: switched off.” with a link to the Channels tab (in the rule list, under Other settings and in the Try a copy result). Saving says so too, in yellow: “Rule saved. Some channels it sends to are switched off, …”. Choosing them is still allowed, so you can set up rules before the channel.
Burst alert
Tells you straight away, without waiting for the summary, when one post is copied many times in a short while. It runs separately from the rules, with its own destinations.
| Field | Default | Range and description |
|---|---|---|
| Burst alert (Alert at once when one post is copied unusually often) | off | Tick to switch on |
| N in “N or more copies within M minutes” | 10 | 2–1,000 copies |
| M (minutes) | 10 | 1–1,440 minutes |
| “Then wait N minutes before alerting about the same post again.” | 60 | 5–1,440 minutes between alerts for the same post |
| Send burst alerts to: | Email / Slack / Discord / Chatwork / Webhook. With none chosen, no burst alert is sent |
- Each time a copy is logged, the post’s copies in the last M minutes are counted from the log. Copies refused by the free plugin’s rate limits aren’t logged, so they don’t count.
- The heading is “
A post was copied N times in M minutes“, with the post title, URL and count. The email subject is “[Site name] A post was copied N times in M minutes“, in plain text.
Where repost alerts go
Under Repost alerts, “Send alerts about pages found on the Reposts tab to:” chooses where to send news of pages the repost search finds. The default is Email. With none chosen, found pages are only listed on the Reposts tab.
05Reposts
Searches the web for paragraphs that were copied repeatedly, to see whether they appear on other sites. Off by default. Searches use your own search API key (Brave Search API or SerpApi), and that service bills you for them directly. Even when it’s on, by default only paragraphs you approve are searched for (see Approving before searching).

What it does and what it sends
- Once a day (first run about an hour after switching on), it picks paragraphs copied from different IP addresses at least Only paragraphs copied at least times in the last 30 days, most copied first. Copies from one IP address count once, however many there are. Paragraphs searched recently (within Search the same paragraph again after) and paragraphs marked Never search are skipped. With Approval on (the default), only approved paragraphs are picked.
- For each paragraph, it looks at the latest ten copies, newest first, for text that appears in the post, and runs one search for the first 40 characters of it:
"that text" -site:your-host-name. Text that isn’t in the post (such as text a visitor made up) and text shorter than 12 characters aren’t searched for. - From the top 10 results it drops your own site and anything under Ignore domains (subdomains included), and records the rest. Each paragraph and URL pair is recorded once.
- If any new pages turned up, it sends “
N pages may contain your content” to the destinations you chose, with your post, the URL found and that page’s title.
Getting an API key
- Brave Search API (
brave.com/search/api): create an account, choose a plan, then create an API key in the dashboard. It uses Brave’s own index and is the cheaper option. - SerpApi (
serpapi.com): create an account; your API key is shown in the dashboard. It returns Google results, which cover Japanese sites better.
Check plans and prices on each service’s site. Either key is accepted as 16–128 letters, digits, _ or -.
Fields (Search settings)
| Field | Default | Range and description |
|---|---|---|
| Repost detection (Search once a day) | off | Stays off unless a search service and an API key are set |
| Search service | — Choose — | Brave Search API or SerpApi (Google) |
| API key | empty | Once saved, only the last four characters are shown (“Saved. Leave empty to keep it.”). Save with the field empty to keep it; tick Remove to clear it. A key in the wrong format gives “Settings saved, but the API key was not in the expected format and was left unchanged.” |
| Searches per day | 20 | 1–200. Upper limit across scheduled and manual searches (resets at midnight in the site’s time zone) |
| Search the same paragraph again after | 7 days | 1–90 days |
| Only paragraphs copied at least | 2 times | 1–100 times (in the last 30 days, from different IP addresses). On screen it reads “times, from different IP addresses, in the last 30 days” |
| Approval (Search only paragraphs I approve) | on | While on, only paragraphs you approve are searched for. Off: paragraphs that meet the conditions are searched for automatically (except those marked Never search) |
| Ignore domains | empty | One per line (up to 200), such as your other sites or partners allowed to republish. Subdomains are included. This site is always ignored |
Above the form you’ll see “Searches today: N of 20.” and “Next scheduled run: date.” (“Scheduled search is off.” when it’s off), then “Searches this month: N. At this rate, about M by the end of the month (at most K with the daily limit). …” Multiply M by your search service’s price per search for an estimate of the month’s cost (prices aren’t part of Pro; check the service’s pricing page).
Approving before searching
Copy events come from visitors’ browsers, so anyone can send them. While Approval is on (the default), a paragraph that meets the conditions isn’t searched for straight away: it is listed under Paragraphs to search on this tab and waits for your decision. Nothing is searched for, and nothing is billed, until you approve it.
| Column | Contents |
|---|---|
| Your post | The post that was copied |
| Phrase | The text that would be searched for once approved (only text that appears in the post). If there’s none, it says “No phrase: the copied text is too short or is not in the post.” |
| Copies | Copies in the last 30 days |
| IP addresses | How many different IP addresses they came from (counted as stored, shortened by the free plugin) |
| Actions | Approve (only when there’s a phrase) and Never search |
- An approved paragraph is searched for from the next scheduled run (or Search now), and again every Search the same paragraph again after days.
- A paragraph marked Never search isn’t searched for even with Approval off.
- Decided paragraphs are listed under Your decisions (Approved or Never search, with the date). Undo puts one back in the waiting list. The table appears whenever decisions exist, with Approval on or off.
- If only waiting paragraphs are left, Search now says “Nothing approved to search for. Paragraphs are waiting for your approval in the list above.”
Costs and the daily limit
- Each search is billed by the search service you chose, to your account. It isn’t included in the price of Pro.
- Searches per day caps the daily number. At the default of 20, the most a month can use is about 600.
- If the search service returns an error such as a rejected key or a reached quota, searching stops for the rest of the day.
- On days with no paragraph due, no search is made (and nothing is billed). With Approval on, paragraphs you haven’t approved never cause a search.
Run now
- Test the API key: runs one search for your site name. “The search service answered with N results. The API key works.” means it’s ready. This search is billed by the service too.
- Search now (up to 5): runs the same process as the scheduled search, up to 5 searches within what’s left of today’s allowance. It reports “Searches made: N. New pages found: N.”
Errors you may see:
| Message | What to do |
|---|---|
| Choose a search service and enter its API key. | The service or the key isn’t set |
| The search service rejected the API key. | The key is wrong, or disabled at that service |
| The search service reports that the quota or rate limit was reached. | Your plan’s limit at that service. Wait until tomorrow or review the plan |
| The search service could not be reached. / The search service returned HTTP N. / …unreadable response. | A network problem or an outage at the service. Try again later |
Reviewing found pages
Pages that may contain your content, at the top of the tab, lists found pages newest first, 50 per page. Filter with New / Confirmed / Ignored / All (New by default).
| Column | Contents |
|---|---|
| Found | Date found |
| Your post | Your post that was copied |
| Page found | The page’s title (opens in a new tab), host name and the search result snippet |
| Searched for | The phrase searched |
| Actions | Confirm (it’s a repost), Ignore (it’s fine), Mark as new (back to unreviewed), Delete (remove the record) |
- Appearing in search results doesn’t make a page a repost. It may be a quotation or a fair mention. Open it and check before deciding.
- An Ignored page isn’t alerted about again when the same paragraph is searched. Delete removes the record, so if the page turns up again it comes back as New and is alerted about again. Use Ignore for pages you want to stay quiet.
- Titles and snippets of found pages are third-party text and are escaped wherever they’re shown. Links carry
noopener noreferrer nofollow, and anything other than http/https links is dropped.
06Export (CSV)
Downloads the log as a CSV file.

| Field | Default | Description |
|---|---|---|
| Dates | 29 days ago – today | Start and end date, both included, in the site’s time zone. An end before the start gives “Enter a valid date range.” |
| Post | All posts | Or one post that has copies in the log |
Download CSV saves rapls-copy-notice-date-time.csv.
- Encoding is UTF-8 with a BOM, so Excel opens Japanese and other non-ASCII text correctly.
- Columns: Date / Post ID / Post title / Post URL / Copied text / Length / IP / User agent / Referrer host / Paragraph fingerprint. Dates are in the site’s time zone.
- Cells starting with
=,+,-,@, a tab or a line break get a leading', so a spreadsheet doesn’t run them as formulas.
07The Network Admin page
On multisite, Network Admin → Settings → Rapls Copy Notice Pro holds the license and network-wide counts. Only super admins can open it.

- License: “One license covers every site in this network. It is registered with the network’s main address.” followed by the same activation form as on a single site.
- Copies across the network (only with an active license): for each site, copies in the last 7 days and 30 days, and the Most copied post (30 days) with its count. Both windows count back from the current time.
- A site’s name opens that site’s Statistics tab. Sites whose log table doesn’t exist yet show “(not set up yet)”.
- 50 sites per page; the last row, Sites on this page, totals that page.
08Updates
Pro updates come from the Rapls Works update server (the license server), not WordPress.org, and arrive in WordPress’s usual update screens. With auto-updates switched on, Pro updates itself like any other plugin.
- Updates need an active license. The license has no expiry, and updates keep arriving while it’s valid. Support is included for a year from purchase.
- Updates are checked every 12 hours. To check now, press Check again on Dashboard → Updates. View details on the Plugins screen shows the changelog.
- The license key never goes in a URL; it’s sent in request headers.
- The ZIP is accepted only over HTTPS from the license server, and its size (under 30 MB) and SHA-256 checksum are checked before installing. If they don’t match you’ll see “The update package failed its integrity check and was not installed.” and nothing is replaced.
- While the free plugin is missing or too old, Pro doesn’t check for updates either. Activate or update the free plugin first.
09Uninstalling
Deactivating Pro on the Plugins screen stops the daily license check and the repost search schedule. No data is removed. Deleting Pro after deactivating removes what Pro created:
| What | Details |
|---|---|
| Settings | Channels (including URLs and tokens), rules, repost search settings (including the API key), the table version record |
| License | Key, email and status (so no credential is left in the database). On multisite, the network-wide copy too |
| Tables | Found pages {prefix}rapls_cn_pro_matches, searched paragraphs {prefix}rapls_cn_pro_checks, approval decisions {prefix}rapls_cn_pro_approvals and the delivery history {prefix}rapls_cn_pro_deliveries (each site’s, on multisite) |
| Temporary data and schedules | Cached license status and update information, burst alert cooldown records, and the schedules for the daily check, repost search, retries and history cleanup |
- Deleting Pro doesn’t free the license seat. If you’ll use it on another site, deactivate it on the License tab first.
- Deleting the free plugin removes the log table and its own options. It leaves Pro’s settings and license (
rapls_cn_pro_*) in place; deleting Pro removes those. - Deleting a site on multisite also drops that site’s Pro tables.
- Large networks: deleting goes through every site in one request and can stop at the server’s time limit. If it does, delete again: it picks up what is left (it gives the same result however often it runs). To check nothing is left, look for tables and options starting with
rapls_cn_pro_in the database. The same goes for deleting the free plugin.
10Troubleshooting
I installed Pro and no tabs appeared
- Look for a red notice about the free plugin at the top of the admin. Without the free plugin, or with a version older than 1.3.19, Pro does nothing.
- On multisite, network-activate both the free plugin and Pro.
A tab says “This feature needs an active Rapls Copy Notice Pro license.”
The license isn’t activated, or the server said it’s no longer valid. Activate it on the License tab. If you’ve just changed domain, activate again on the new address.
Nothing arrives in Slack (or another channel)
- Check that Send notifications here is still ticked after saving (it switches off without a URL or token).
- Try a test message. If the test arrives but notifications don’t, check the Rules tab: with any rule on, copies only go to the destinations of rules they match.
- With hourly summaries, messages come once an hour. Summaries run on WP-Cron, so on a quiet site they go out with the first visit after the hour.
- If even the test fails, check the URL, token and room ID, and that your server can make outbound HTTPS requests.
- Look at the Delivery history on the Channels tab: a failed delivery shows its reason, and Send again now sends it once you’ve fixed the cause.
- If the Rules tab says “Nothing is sent to …: switched off.”, switch that channel on. Try a copy shows where copies actually go.
Emails stopped coming
If a rule’s Send to doesn’t include Email, copies matching that rule aren’t in the email. Copies matching no rule aren’t sent at all when Copies matching no rule is Do not notify.
No burst alert
Check that Burst alert is on and Send burst alerts to: has at least one destination. Once a post has been alerted about, it isn’t again until the wait (60 minutes by default) has passed.
The webhook signature doesn’t match
Since Pro 1.1.4 the signature covers “the X-RCN-Timestamp value + . + the body” (examples); a signature computed over the body alone won’t match. Compute it over the raw body bytes as received. Decoding and re-encoding the JSON, reordering keys or tidying whitespace all change it. Also check for stray spaces around the secret, and that the receiver’s clock is within five minutes, or the timestamp check will refuse the request.
The paragraph table in Statistics is empty
That post only has copies without a paragraph fingerprint: copies on non-HTTPS pages, from outside a paragraph, or recorded before free version 1.2 (details).
The repost search doesn’t run
- Repost detection won’t switch on without both a search service and a key.
- Check “Next scheduled run”. It runs on WP-Cron, so it’s late on quiet sites.
- There may be no paragraph due. Lower Only paragraphs copied at least, or wait for more fingerprinted copies.
- If “Searches today” has reached the limit, no more searches run until tomorrow.
Excel opens the CSV in a single column
The separator is a comma. If your regional settings use another separator, import it with “Data → From Text/CSV” and choose comma as the delimiter.
11FAQ
Is it a subscription? Does it stop after a year?
It’s a one-time purchase. The license doesn’t expire and doesn’t stop after a year. Support is included for a year from purchase.
What happens if the license server goes down?
Nothing happens to your site. Pro keeps running while the server can’t be reached. It stops only when the server explicitly says the license is no longer valid.
Does Pro block copying?
No. Like the free plugin, it has no feature that blocks copying, right-click or text selection. It notifies, records and searches, nothing more.
Does Pro send visitor data anywhere?
Channels you switch on receive the notification contents (copied text, post, shortened IP, user agent). The repost search sends the search service only text from your own post and your host name. Nothing goes to either until you switch it on.
Can editors and authors use it?
All Pro tabs are for administrators (manage_options). On multisite, super admins manage the license.
Can I get a refund?
See the refund policy.
