Deftmind Hookwright: reference & troubleshooting.
The second half of the guide. If you are setting up your first form, start with Part 1. (Pro) marks anything needing the paid add-on.
Bringing information in · Posts and pages · Draft posts (Pro) · Your existing form · Making it look right · When something goes wrong · Security software · Shortcode reference · Field names · Keeping your site safe · FAQ · Events · Glossary
← Back to Part 1: getting started · Part 3: sending a webhook when you publish (Pro) →
Bringing information into your site
This direction works the other way round: your platform sends information whenever it likes, and your site displays it.
Step 1 — Turn the door on
The plugin refuses all incoming information until you set a password. This is deliberate.
- Go to Deftmind Hookwright → Settings.
- Find Inbound shared secret.
- Type a long random password — at least 16 characters.
- Click Save Changes.
- Copy the Endpoint URL shown just above it.
Common mistake
Leaving the secret empty. Nothing will arrive and it will look broken. It is not broken — it is locked.
Step 2 — Send something
Have your workflow send a POST to that address, with a header named X-Hookwright-Secret containing your secret, and a body like this:
{ "channel": "health-news", "title": "New clinic opening in Kano", "body": "## Opening times\n\nThe clinic opens on **Monday**." }
channel is just a label you invent — a named stream. Channels create themselves the first time something arrives. Leave it out and it goes to a channel called default.
Step 3 — Show it on a page
No data yet.
No data yet.
No data yet.
The first shows the most recent item, the second shows a list, and the third updates itself every 30 seconds without a reload. Full options are in the shortcode reference.
How much is kept
Each channel remembers a set number of recent items — 10 by default, adjustable from 1 to 50 under Settings → Payloads kept per channel. Older items drop off automatically. Any posts already created from them are unaffected.
Turning what arrives into posts and pages
- Go to Deftmind Hookwright → Channels.
- In Add a rule, choose the Channel. You may name one that does not exist yet.
- Choose whether to create a Post or a Page.
- Choose a Status: Draft (always available), Pending review (Pro), or Publish immediately (Pro).
- Choose an Author — a real user allowed to write posts.
- For pages only, optionally choose a Parent page.
- Optionally choose a Default featured image.
- Click Add rule.
Strong recommendation
Start with Draft. Review a few, then switch to automatic publishing only once you trust the workflow. Automatic publishing means your secret alone can put content live on your site.
| In the message | Becomes |
|---|---|
title | The post title |
body | The post content, with Markdown formatted properly |
categories | Attached to existing categories only. Unknown names are skipped. |
tags | Attached, and created if they do not exist. |
| An image field | The featured image |
Duplicates are prevented automatically: the same channel, title and content will never create a second post, so a retry cannot double-publish.
Featured images
image_id— the ID of something already in your Media Library. Free, and the safest.image_base64— the image data sent directly. (Pro), and needs Inline image data switched on. Best when an AI generates the picture.image— a web address to download from. (Pro), and only from hosts you list under Allowed image hosts. Empty by default, so this is off until you allow a host.- The rule’s default image — used when nothing else is supplied.
Every image is checked to confirm it really is a JPEG, PNG, GIF or WebP by examining the file itself, not by trusting its name. Oversized images are skipped and the post is still created.
Turning replies into draft posts (Pro)
This works the other way round: it saves the answers your workflow gives to form submissions.
- Open a form under Deftmind Hookwright → Forms.
- Scroll to Publish replies.
- Tick to enable it, and choose the post type, status, author and default image.
- Click Save form.
“Create as” offers every post type on your site — Post, Page, and any custom post type you have, such as Products, Events or Staff. A form’s answers can be filed straight into whichever kind of content they belong to.
- Works with Wait for and show the reply and with Callback, with no extra setup in either case.
- Not available in chat mode, because every chat message is an answer and you would drown in drafts.
- Identical answers never create a second post.
Using this to generate content
This is what people usually reach for it: your workflow writes something, and it lands in WordPress as a post you can review.
The shape is always the same, and nothing about it is specific to any one kind of workflow:
- A visitor fills in the form — a topic, a question, a brief.
- Your workflow does whatever it does with that. It might look something up in a database, assemble a report from several sources, run a calculation, or call a language model to write an article.
- It sends back an answer carrying a title, the body in Markdown, and optionally categories and tags.
- Deftmind Hookwright shows the visitor the answer and saves it as content.
Two things make this safe to leave running
Draft is the default status. Generated content waits for you to read it before anything goes live. Only change that once you trust the workflow.
Identical answers never create a second post, so a retried submission cannot double-publish.
If the work takes a while — a long article, or several steps — use Callback so the visitor is not left waiting on an open connection. Publishing works exactly the same either way, with no extra setup.
You can also start this from the other direction, with no visitor involved at all: have a scheduled job in your automation platform send finished content to your site’s inbound address, and turn on publishing for that channel (see Turning what arrives into posts and pages). Same result, no form.
Using a form you already have
If you already have a form and do not want to rebuild it, you can hand its submissions to Deftmind Hookwright. This step needs someone comfortable editing HTML.
<form data-hookwright-bridge
data-hookwright-endpoint="ask-health"
data-hookwright-response="#my-answer">
<input type="text" name="question" />
<button type="submit">Ask</button>
</form>
<div id="my-answer"></div>
data-hookwright-endpointchooses which saved form’s settings to use — including its response mode, so callback works here too. The web address always stays on the server; the browser never sees it.data-hookwright-responseis optional. Without it, the answer appears just after the form.
Important
Do not add this to forms built by WPForms, Gravity Forms, Contact Form 7 or a page builder. Those run their own submission code and the two will fight.
Making it look right
Without writing any code
| Setting | What it does |
|---|---|
| Accent colour | Tints the button and the form’s border. |
| Layout | Stacked puts labels above boxes. Inline puts everything on one row, like a search box. |
| Border | Match the accent colour, pick a custom colour, or remove it. |
| Chat area colour | The background behind chat messages. |
| Extra CSS class | For a designer to target this one form. |
None of these change what is sent or received. They are purely visual.
With CSS
Go to Appearance → Customize → Additional CSS.
/* Remove the card, leaving plain fields */
.hookwright-form { border: none; padding: 0; background: transparent; }
/* Change just the border colour */
.hookwright-form { border-color: #cccccc; }
/* Target one form using its Extra CSS class */
.hookwright-form.my-form { border-radius: 0; }
Useful class names: .hookwright-form, .hookwright-submit, .hookwright-response, .hookwright-thread, .hookwright-bubble-user, .hookwright-bubble-assistant, .hookwright-items, .hookwright-item.
When something goes wrong
What visitors see
| What happened | What they see |
|---|---|
| Your workflow was too slow | This is taking longer than usual. Please try again in a moment. |
| Your workflow could not be reached | The service is temporarily unavailable. |
| Your workflow answered but sent nothing | That went through, but no reply came back to show. |
| A callback deadline passed | No reply arrived in time. Please try again. |
Their typed text is always kept so they can retry without retyping.
Adding your own message
- Go to Settings → If a send fails, add for the whole site, or set it per form.
- Type something like: You can also email us at hello@example.com and we will reply personally.
- Save.
Plain text only, up to 500 characters. It appears only on genuine failures.
How you find out
Three places, all administrator-only, and all appearing only when something has actually gone wrong:
- Settings → Recent send problems — the full picture, kept for 24 hours.
- A Dashboard widget — the three most recent problems.
- An admin notice — elsewhere in the admin area.
Troubleshooting checklist
| Problem | Try this |
|---|---|
| Nothing happens when I submit | Check the Form ID in the shortcode matches the form exactly. |
| “This form is not configured” | The Webhook URL is empty or was rejected. It must be a public address. |
| Visitors see an error but my test works | Look at Recent send problems. A test and a real submission take different routes. |
| A field is not arriving | Check its name is listed in the Fields box. Unlisted fields are dropped. |
| Nothing arrives from my platform | The Inbound shared secret is missing, or the header name is misspelled. It must be exactly X-Hookwright-Secret. |
| The answer shows as a table when I wanted prose | Your field name is not one the plugin recognises, or set Response rendering to Markdown. |
| Callback answers never arrive | Confirm your workflow reads the return address from each message, then read the next section. |
| Everything worked, then stopped | Read the next section. |
Security software that can break the plugin
This section exists because it is genuinely hard to diagnose, and it is not a fault in the plugin.
Many hosts and security services put a bot check in front of your site — a page saying “Checking your browser before accessing” that runs briefly before letting you through. A real person’s browser passes it without noticing.
Your automation platform is not a browser. It cannot pass that check. If your host applies it to the address your platform is sending to, then:
- Information sent into your site never arrives.
- Callback answers never arrive.
- In the worst cases, ordinary form submissions fail now and then and visitors see “Something went wrong.”
How to tell if this is your problem
Everything looks correct, and your automation platform reports an error or a 403 when it tries to reach your site. Ask your host, or check your security plugin, and look at what happens to this address:
https://your-site.com/wp-json/
If a bot check or firewall rule stands in front of it, that is your answer.
How to fix it
Ask your host, or use your security plugin’s settings, to exempt this address from bot checks and firewall rules:
/wp-json/hookwright/
That is narrow enough to be safe. It exempts only this plugin’s own doors, which have their own passwords, and leaves the rest of your site protected.
Services that commonly do this: Cloudflare (Bot Fight Mode, WAF rules), Hostinger, SiteGround, WP Engine, Wordfence, Sucuri, All In One WP Security.
Tip
If you are testing and things behave inconsistently — working once, failing the next time — suspect this before suspecting the plugin.
Shortcode reference
— put a form on a page
| Option | Values | Notes |
|---|---|---|
id | a Form ID | Leave out to use the site-wide settings instead. |
response_render | auto, markdown, table, json | Only used when id is left out. |
— put a form’s answer somewhere else
| Option | Notes |
|---|---|
id | The Form ID this container belongs to. |
class | Extra CSS class names. |
Works with callback mode — see where the answer appears.
No data yet.
— show information sent into your site
No data yet.
| Option | Values | Notes |
|---|---|---|
channel | any name | Which stream to show. Default default. |
mode | latest, list | One item, or a list. |
count | 1 to 20 | How many items a list shows. |
order | newest, oldest | Sort direction. |
offset | 0 to 49 | Skip this many first. |
field | a path | Show only part, such as field="stats.views". |
render | auto, markdown, table, json | How to display it. |
refresh | 0, or 5 and above | Seconds between automatic checks. 0 means never. |
archive | a web address | Where category and tag links point. |
meta | auto, none | none hides category and tag labels. |
Letting people attach a file
Add a field of type file and the visitor gets a button to attach something:
receipt | Your receipt | file:pdf,png | required
The part after the colon lists what you will accept. Leave it off — just file — and everything the plugin can check is accepted:
PDF, JPEG, PNG, GIF, WebP, Word, Excel, PowerPoint, plain text and CSV. Nothing else. Naming a type that is not on that list simply drops it from your list rather than allowing it, and the report under the Fields box tells you so.
Every file is checked against what is inside it, not what it is called
Renaming something to .png does not get it through. Even a spreadsheet renamed to .docx is refused, because Word, Excel and PowerPoint files are told apart by their actual contents.
Two things are never accepted at all: SVG images, because they can carry hidden instructions, and zip files, because there is no way to tell a harmless one from a harmful one.
Nothing is stored on your site
Not in the Media Library, not in your uploads folder, not in your database. Each file is checked, passed straight to your webhook, and forgotten. There is no link for anyone to find later and nothing to tidy up.
What your workflow receives
Attachments do not arrive among the other answers. They come in a separate group called attachments, so a workflow that already reads your form’s answers cannot break when you add a file field.
{ "fields": { "full_name": "Sam" }, "attachments": { "receipt": { "filename": "receipt.pdf", "type": "application/pdf", "size": 184320, "data": "JVBERi0xLjcK…" } } }
Look under attachments, not fields. The data part is the file itself, written the way files are normally sent inside a message like this. Most automation platforms have a step that turns it back into a file — in n8n it is Convert to File → Base64 to File.
Size, and what your host allows
You choose the limit on the Settings screen, and it starts at 2 MB per file. Some hosts cannot carry that much, so the screen tells you what your server will really accept, and visitors are held to the real figure rather than discovering it half way through an upload. Up to five files can be sent in one submission.
Before you promise anyone privacy
The file reaches your workflow intact and will usually sit in that platform’s history until you delete it or it ages out. If someone sends you a passport scan, that scan is in your automation tool’s logs.
Ask only for files you actually need, and say in your privacy policy what happens to them. “We do not store it” is true of this plugin and not necessarily true of the service you forward it to.
Field names the plugin understands
Whenever your workflow sends something — an answer to a form, or information into your site — the plugin looks for these names. Capital letters, underscores, dashes and spaces are ignored.
| What it is | Names it accepts |
|---|---|
| The main text | body, markdown, content, text, answer, reply, message, output, article, description, summary |
| A heading | title, post_title, subject, heading, headline, name, label |
| Categories | categories, category, cats, sections, topics |
| Tags | tags, tag, keywords, terms, labels |
| An image | image_id (free), image_base64 (Pro), image / featured_image / image_url (Pro) |
| The stream name | channel — only when sending information into your site |
Wrappers removed automatically: data, payload, result, results, json, output, item, items, record, fields, attributes, object, and a list containing exactly one item. Up to four layers deep.
Nothing is required. If none of these names appear, your information is displayed as a labelled table instead of an article.
How your site is kept safe
- The incoming door is locked by default. It stays shut until you set a password of at least 16 characters.
- Your webhook address and any password attached to it never reach the visitor’s browser. Everything is sent from your server.
- Your site will not be tricked into contacting itself or your internal network. Addresses are checked when saved and again every time they are used.
- Failure messages give nothing away. A blocked address and an unreachable one produce exactly the same message, so nobody can use your form to map your network.
- Nothing sent to your site can run code on your page. Text is displayed as text; HTML in a message is shown as characters, not executed.
- Every image is verified by examining the file itself.
- Forms are rate-limited per visitor, and a hidden trap field quietly absorbs automated spam.
- Callback answers use two separate one-time passwords. One goes to your automation platform and can only deliver an answer. The other stays in the visitor’s browser and is the only thing that can read it. Knowing one never gives you the other, and both expire within minutes.
Reporting a security problem
If you believe you have found a vulnerability, please email support@deftmindlabs.com rather than posting it publicly, so it can be fixed before anyone can act on it. Reports are welcome, taken seriously, and acknowledged.
Frequently asked questions
| Question | Answer |
|---|---|
| Can I get a refund? | Billing is handled by Freemius as merchant of record, and their refund policy governs the transaction. The option chosen for these products is No refunds: because the plugin is a digital download, refunds are not generally offered. A full refund is given on request within 14 days only if the plugin was never downloaded. Requests after download are considered individually at our discretion, and must be made within 14 days of purchase. The paid 7-day trial exists precisely so you can evaluate the plugin in full before any charge is taken. |
| Do I need an AI subscription? | No. The plugin has no AI of its own. If your workflow uses AI, that is arranged on your platform. |
| Where are my API keys stored? | Not here. Any password you set for your webhook stays on your server and is never sent to a browser. |
| Can I have more than one form? | Yes. The free plugin allows one saved form; Pro raises that considerably. You can always use the site-wide settings without creating a named form. |
| Can two forms use different workflows? | Yes. Each form has its own address and settings. |
| Will this slow my site down? | No. Nothing happens until someone submits a form or your platform sends something. Callback is lighter than waiting, because your server is not held open. |
| Can visitors see my webhook address? | No. Submissions go to your own server first, which passes them on. |
| What if my workflow is down? | The visitor sees a polite failure message with their text preserved, and you get a record under Recent send problems. |
| Does the answer stay after a reload? | No. Use Publish replies if you want it saved. |
Can I display a form answer with ? | No. That is only for information your platform sends in. Use for form answers. |
| My workflow takes three minutes. Possible? | Yes — use Callback mode and set the deadline high enough. |
| Can I use callback with chat? | Not currently. Chat forms wait for the reply directly. |
| How do I test a callback without a real visitor? | Put the form on a draft page and preview it yourself. The Test webhook button carries no return address, so it cannot test the reply itself. |
| Is my visitors’ data stored? | Form submissions are passed to your workflow and not stored. Chat conversations are never stored. Only information sent into your site is stored, and only as much as your retention setting allows. |
Events — sending what happens on your site
An event is a moment your automation platform should know about — a visitor landing on a page, clicking a button, or a post going live. Instead of polling on a schedule, your automation receives them the moment they happen.
Go to Deftmind Hookwright → Events, enter a webhook URL, and tick Enable website events. Two kinds are available and each is independent:
| Kind | What fires it |
|---|---|
| Browser events | A visitor loads a page, clicks an element, or follows a link — detected in their browser |
| WordPress events | A post publishes for the first time, a comment is approved, or someone registers an account |
Every payload includes a source field — "browser" or "wordpress" — so one workflow can handle both with a simple branch.
Browser events — what your visitors do
Each rule has a label (what fires it in your workflow), a trigger (Page loaded, Element clicked, or Link followed), a URL pattern (which pages), and optionally a CSS selector for click rules. Uncheck a row to pause it without deleting it.
URL patterns: / = homepage only · /shop/ = that page exactly · /shop/* = that page and everything below · * = every page.
Events only fire after your consent tool signals agreement by default. Change Consent to Do not require a consent signal if your setup does not need this. To capture data from a landing URL (for example an order ID after checkout), name the parameter under Capture query parameters.
Sample payload — browser event:
{
"event_id": "f840100a-0f5f-4cc6-9a57-08d6f50d9324",
"event_name": "page_view",
"event_time": "2026-08-08T22:20:40+00:00",
"source": "browser",
"page_url": "https://example.com/",
"page_title": "Welcome to our site",
"referrer_url": "https://google.com/",
"utm": { "utm_source": "google", "utm_medium": "organic", "utm_campaign": "" },
"session_attribution": { "utm_source": "google", "utm_medium": "organic" },
"event_data": { "rule_name": "Homepage viewed" }
}
| Field | What it contains |
|---|---|
event_id | Unique ID — use it to deduplicate retries |
event_name | page_view, click, or redirect |
source | Always "browser" for this kind |
page_url / page_title | The page the visitor was on |
referrer_url | Where they came from — empty if they typed the address directly |
utm / session_attribution | Campaign parameters from this page’s URL, and the first ones seen this session |
event_data.rule_name | The label you gave this rule |
WordPress events — what happens inside WordPress
No rules to write — tick which types to send: post published (first time only), comment approved, user registered. A post fires once; taking it back to draft and republishing does not fire again. Password-protected posts and autosaves are ignored.
Sample payload — WordPress event:
{
"source": "wordpress",
"site": "https://example.com",
"data": {
"post_id": 95,
"post_type": "post",
"title": "Our new product is here",
"url": "https://example.com/our-new-product/",
"excerpt": "A short preview of the post.",
"author_id": 1,
"author_name": "admin",
"published": "2026-08-08T21:56:42+00:00",
"categories": ["News", "Products"],
"tags": ["launch"]
}
}
The full post body is not included. Your workflow can fetch it from the REST API using the url in the payload. Email addresses in comment and registration events are off by default — turn them on in the Events settings if you need them.
Nothing is stored on your site. Each event is forwarded to your webhook and then forgotten — no cookie set, no visitor identifier created, no database row written.
Sending a webhook when you publish (Pro)
Everything above is about bringing information into your site. The opposite direction — sending a webhook out the moment a post, page or custom post type is published, with your own custom fields and optional signing — now has a page of its own.
Glossary
| Term | Meaning |
|---|---|
| Automation platform | The outside service where your logic runs — n8n, Make, Zapier and so on. |
| Callback | Answering later, by sending the answer to an address, instead of staying on the line. |
| Channel | A named stream of information sent into your site. |
| Deadline | How long a visitor waits for a callback answer. |
| Endpoint | A web address that accepts information. |
| Field | One box on a form. |
| JSON | A simple text format for exchanging information between computers. |
| Markdown | Simple formatting for text. |
| Payload | One package of information. |
| POST | The kind of web message used to send information somewhere. |
| Return URL | The one-time address your workflow sends a callback answer to. |
| Shortcode | Text in square brackets that WordPress turns into something real. |
| Webhook | A web address that accepts information sent by another computer. |
| Workflow | One piece of automation logic you have built. |
