{"id":362665,"date":"2026-09-05T06:46:48","date_gmt":"2026-09-05T06:46:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/recourse-ai-chatbot-for-customer-support\/"},"modified":"2026-09-05T06:54:46","modified_gmt":"2026-09-05T06:54:46","slug":"recourse","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/recourse\/","author":18136256,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.3.0","stable_tag":"0.3.0","tested":"7.1","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"Recourse - AI Chatbot for Customer Support","header_author":"Ibrahim Hajjaj","header_description":"A support agent that answers from your own pages and products, with citations. Runs on your server; no content leaves it except the question you send to your own model provider.","assets_banners_color":"3f4555","last_updated":"2026-09-05 06:54:46","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/ibrahimhajjaj\/recourse","header_author_uri":"https:\/\/github.com\/ibrahimhajjaj","rating":0,"author_block_rating":0,"active_installs":0,"downloads":35,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.3.0":{"tag":"0.3.0","author":"ibrahimhajjaj","date":"2026-09-05 06:54:46","revision":3682190}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3682186,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3682186,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3682186,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3682186,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.3.0"],"block_files":[],"assets_screenshots":{"screenshot-1.jpg":{"filename":"screenshot-1.jpg","revision":3682186,"resolution":"1","location":"assets","locale":"","width":1427,"height":840},"screenshot-2.jpg":{"filename":"screenshot-2.jpg","revision":3682186,"resolution":"2","location":"assets","locale":"","width":1427,"height":840},"screenshot-3.jpg":{"filename":"screenshot-3.jpg","revision":3682186,"resolution":"3","location":"assets","locale":"","width":1427,"height":840},"screenshot-4.jpg":{"filename":"screenshot-4.jpg","revision":3682186,"resolution":"4","location":"assets","locale":"","width":1427,"height":840}},"screenshots":{"1":"A visitor's question answered from the site's own Shipping page, with a numbered citation under the answer naming the page and the section it came from.","2":"The same conversation asking something the site does not document. The assistant says so and hands over an email address instead of inventing an answer.","3":"The settings screen: which post types to index, the persona and tone, the model endpoint, and the accent colour.","4":"Rebuilding the index, which reports how many documents it holds and how large it is."}},"plugin_section":[],"plugin_tags":[191735,2364,2369,4049,2379],"plugin_category":[47],"plugin_contributors":[262678],"plugin_business_model":[],"class_list":["post-362665","plugin","type-plugin","status-publish","hentry","plugin_tags-ai-chatbot","plugin_tags-chatbot","plugin_tags-customer-support","plugin_tags-helpdesk","plugin_tags-live-chat","plugin_category-education-and-support","plugin_contributors-ibrahimhajjaj","plugin_committers-ibrahimhajjaj"],"banners":{"banner":"https:\/\/ps.w.org\/recourse\/assets\/banner-772x250.png?rev=3682186","banner_2x":"https:\/\/ps.w.org\/recourse\/assets\/banner-1544x500.png?rev=3682186","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/recourse\/assets\/icon-128x128.png?rev=3682186","icon_2x":"https:\/\/ps.w.org\/recourse\/assets\/icon-256x256.png?rev=3682186","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/recourse\/assets\/screenshot-1.jpg?rev=3682186","caption":"A visitor's question answered from the site's own Shipping page, with a numbered citation under the answer naming the page and the section it came from."},{"src":"https:\/\/ps.w.org\/recourse\/assets\/screenshot-2.jpg?rev=3682186","caption":"The same conversation asking something the site does not document. The assistant says so and hands over an email address instead of inventing an answer."},{"src":"https:\/\/ps.w.org\/recourse\/assets\/screenshot-3.jpg?rev=3682186","caption":"The settings screen: which post types to index, the persona and tone, the model endpoint, and the accent colour."},{"src":"https:\/\/ps.w.org\/recourse\/assets\/screenshot-4.jpg?rev=3682186","caption":"Rebuilding the index, which reports how many documents it holds and how large it is."}],"raw_content":"<!--section=description-->\n<p>Recourse is an AI chatbot for customer support that answers out of your own content. It reads your published posts, pages and any public custom post types, builds a search index from them, and answers visitors' questions from that index. Every answer carries numbered citations pointing at the pages it came from, so a visitor can check it and you can see where a wrong answer came from.<\/p>\n\n<p>Nothing is indexed that a visitor could not already read. Drafts, private posts, password-protected posts and post types you did not tick are all left out, and a <code>recourse_index_post<\/code> filter is there for anything else your site needs to exclude.<\/p>\n\n<p>Retrieval runs on your own server and needs no account and no credential. Generating the answer text does: you supply an OpenAI-compatible endpoint and its key, and you pay whatever that provider charges. Until you do, the plugin makes no external request at all.<\/p>\n\n<p>Under Settings there is a Model Provider picker that fills the endpoint in for\nyou. These all speak the OpenAI chat format and all work:<\/p>\n\n<ul>\n<li>OpenAI, <code>https:\/\/api.openai.com\/v1<\/code><\/li>\n<li>Anthropic (Claude), <code>https:\/\/api.anthropic.com\/v1<\/code><\/li>\n<li>xAI (Grok), <code>https:\/\/api.x.ai\/v1<\/code><\/li>\n<li>DeepSeek, <code>https:\/\/api.deepseek.com\/v1<\/code><\/li>\n<li>Groq, <code>https:\/\/api.groq.com\/openai\/v1<\/code><\/li>\n<li>OpenRouter, <code>https:\/\/openrouter.ai\/api\/v1<\/code><\/li>\n<li>Mistral, <code>https:\/\/api.mistral.ai\/v1<\/code><\/li>\n<li>Moonshot (Kimi), <code>https:\/\/api.moonshot.ai\/v1<\/code><\/li>\n<li>Alibaba Qwen (DashScope), <code>https:\/\/dashscope.aliyuncs.com\/compatible-mode\/v1<\/code><\/li>\n<li>Ollama on your own server, <code>http:\/\/localhost:11434\/v1<\/code><\/li>\n<\/ul>\n\n<p>The list is a convenience, not a limit. Anything else speaking the same format\nworks if you type its address in, and the boxes stay editable after you pick.<\/p>\n\n<p>The key belongs in <code>wp-config.php<\/code> rather than the database if you would rather it did not travel in a backup:<\/p>\n\n<pre><code>define( 'RECOURSE_API_KEY', 'your-key' );\n<\/code><\/pre>\n\n<h3>External services<\/h3>\n\n<p>Recourse needs an OpenAI-compatible chat completions endpoint to write an answer. None ships with the plugin and none is contacted until you enter a base URL under Settings, so an unconfigured install makes no external request at all. You supply the base URL and the key, so the service contacted is whichever one you choose.<\/p>\n\n<ul>\n<li>When it is called: on each visitor question submitted through the chat widget, and once each time an administrator presses Test Connection on the settings screen.<\/li>\n<li>What is sent: the visitor's question, up to twelve previous turns of the same conversation, the persona text you configured, your business name (your site title unless you change it), and the passages, titles and permalinks from your published content that matched the question. Nothing is sent from drafts, private posts, or post types you did not tick.<\/li>\n<li>What comes back: one block of answer text, shown to the visitor. Nothing else from the response is kept.<\/li>\n<\/ul>\n\n<p>Whichever provider you point it at, that provider's own terms of service and privacy policy govern the data you send them. The settings screen offers the following as one-click choices, and each one is a separate company with its own terms:<\/p>\n\n<ul>\n<li>OpenAI, api.openai.com: <a href=\"https:\/\/openai.com\/policies\/terms-of-use\/\">terms of use<\/a>, <a href=\"https:\/\/openai.com\/policies\/privacy-policy\/\">privacy policy<\/a><\/li>\n<li>Anthropic, api.anthropic.com: <a href=\"https:\/\/www.anthropic.com\/legal\/commercial-terms\">commercial terms<\/a>, <a href=\"https:\/\/www.anthropic.com\/legal\/privacy\">privacy policy<\/a><\/li>\n<li>xAI, api.x.ai: <a href=\"https:\/\/x.ai\/legal\/terms-of-service-enterprise\">enterprise terms of service<\/a>, <a href=\"https:\/\/x.ai\/legal\/privacy-policy\">privacy policy<\/a><\/li>\n<li>DeepSeek, api.deepseek.com: <a href=\"https:\/\/cdn.deepseek.com\/policies\/en-US\/deepseek-terms-of-use.html\">terms of use<\/a>, <a href=\"https:\/\/cdn.deepseek.com\/policies\/en-US\/deepseek-privacy-policy.html\">privacy policy<\/a><\/li>\n<li>Groq, api.groq.com: <a href=\"https:\/\/groq.com\/terms-of-use\/\">terms of use<\/a>, <a href=\"https:\/\/groq.com\/privacy-policy\/\">privacy policy<\/a><\/li>\n<li>OpenRouter, openrouter.ai: <a href=\"https:\/\/openrouter.ai\/terms\">terms of service<\/a>, <a href=\"https:\/\/openrouter.ai\/privacy\">privacy policy<\/a><\/li>\n<li>Mistral AI, api.mistral.ai: <a href=\"https:\/\/legal.mistral.ai\/terms\/commercial-terms-of-service\">commercial terms of service<\/a>, <a href=\"https:\/\/legal.mistral.ai\/terms\/privacy-policy\">privacy policy<\/a><\/li>\n<li>Moonshot AI (Kimi), api.moonshot.ai: <a href=\"https:\/\/platform.kimi.ai\/docs\/agreement\/modeluse\">terms of service<\/a>, <a href=\"https:\/\/platform.kimi.ai\/docs\/agreement\/userprivacy\">privacy policy<\/a><\/li>\n<li>Alibaba Cloud Model Studio, dashscope.aliyuncs.com: <a href=\"https:\/\/www.alibabacloud.com\/help\/en\/legal\/latest\/alibaba-cloud-international-website-product-terms-of-service\">product terms of service<\/a>, <a href=\"https:\/\/www.alibabacloud.com\/help\/en\/legal\/latest\/alibaba-cloud-international-website-privacy-policy\">privacy policy<\/a><\/li>\n<\/ul>\n\n<p>Ollama is also offered, and is not an external service: it runs on your own server at localhost, so nothing leaves the machine.<\/p>\n\n<p>Any other OpenAI-compatible endpoint works too. Choose \"Other\" and enter its address, in which case the service contacted is the one you named and its own terms apply.<\/p>\n\n<h3>Works with what your site already has<\/h3>\n\n<p>On WordPress 6.9 and later the assistant registers itself with the Abilities\nAPI, so other tools on your site can use it, and it can call abilities other\nplugins register once you list them. Nothing is called without you naming it,\nand an ability marked as destructive is refused even then.<\/p>\n\n<p>On WordPress 7.0 and later, if your site already has an AI connector set up\nunder Settings, the assistant will use it and you do not need to enter an\nendpoint or a key here at all.<\/p>\n\n<h3>Telling visitors they are talking to software<\/h3>\n\n<p>The chat window says \"Automated assistant. Answers can be wrong.\" under the\nassistant's name. The EU AI Act has required that disclosure of visitor-facing\nchatbots since 2 August 2026, and the duty falls on the site rather than on the\nplugin, so the wording is yours to change through the <code>recourse_ai_disclosure<\/code>\nfilter. It is there by default rather than absent.<\/p>\n\n<h3>Source code<\/h3>\n\n<p>The widget script shipped as <code>assets\/recourse.min.js<\/code> is built from the TypeScript sources at https:\/\/github.com\/ibrahimhajjaj\/recourse, under <code>packages\/widget\/src<\/code>. The readable build is shipped alongside it as <code>assets\/recourse.js<\/code>. Build both yourself with <code>npm install &amp;&amp; npm run build<\/code> in <code>packages\/widget<\/code>, then take them from <code>dist\/wordpress<\/code>. That is the same source as the general build, compiled without the loader that would fetch a voice runtime from a content delivery network, since a plugin may not fetch code from another host.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin to <code>\/wp-content\/plugins\/recourse<\/code>, or install it through the plugins screen.<\/li>\n<li>Activate it.<\/li>\n<li>Go to Settings, then Recourse. Enter your model endpoint and key, and tick the post types to index.<\/li>\n<li>Press Rebuild Index. A large site is indexed in batches in the background.<\/li>\n<li>Tick Enable the assistant.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20it%20work%20without%20an%20api%20key%3F\"><h3>Does it work without an API key?<\/h3><\/dt>\n<dd><p>Retrieval does, and so does the index. Writing the answer does not: that needs a model endpoint and a key, which you supply.<\/p><\/dd>\n<dt id=\"what%20content%20leaves%20my%20site%3F\"><h3>What content leaves my site?<\/h3><\/dt>\n<dd><p>The passages that matched the question, the question, the recent conversation, and the persona text. See the External services section above for the full list. Your site is not uploaded anywhere.<\/p><\/dd>\n<dt id=\"can%20i%20hide%20the%20widget%20on%20some%20pages%3F\"><h3>Can I hide the widget on some pages?<\/h3><\/dt>\n<dd><p>Yes. Return false from the <code>recourse_show_widget<\/code> filter.<\/p><\/dd>\n<dt id=\"how%20large%20a%20site%20can%20it%20index%3F\"><h3>How large a site can it index?<\/h3><\/dt>\n<dd><p>The index is built in batches on WP-Cron, so the size of the site is not the limit. The index file is read on each question, so a very large catalogue will want an object cache.<\/p><\/dd>\n<dt id=\"does%20it%20work%20on%20multisite%3F\"><h3>Does it work on multisite?<\/h3><\/dt>\n<dd><p>Each site in a network has its own settings and its own index. Uninstalling removes the data from every site in the network.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.3.0<\/h4>\n\n<ul>\n<li>The chat script no longer names a content delivery network. The widget can\nload a voice runtime from one when a site turns calls on; the plugin never\ndoes, so that loader is compiled out of the copy shipped here and the plugin\nfetches nothing from another host.<\/li>\n<li>Each provider in the settings list now names its own terms of service and\nprivacy policy, since the service contacted is whichever one you pick.<\/li>\n<li>Moonshot's two links pointed at pages that have moved to the Kimi platform.<\/li>\n<li>An icon and a banner, so the listing is not a grey circle.<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>The answer ability no longer offers the model any action, which is what its\nread-only annotation always claimed. It was handing over every action a site\nhad registered, including ones that write.<\/li>\n<li>The settings script is enqueued rather than printed into the page.<\/li>\n<li>A customer pasting an ordinary tracking link is no longer refused. The guard\nthat strips links held a literal control character where a word boundary was\nmeant, so it never stripped anything.<\/li>\n<li>The repeated-character check had never matched anything, for the same reason.<\/li>\n<li>Three findings the plugin dropped that the Node engine reports: one signal per\nmatching phrase rather than only the highest, a signal when invisible\ncharacters are found rather than silently cleaning them, and an invented phone\nnumber in an answer.<\/li>\n<li>The passage screen read a key the retriever never set, so it had never refused\na page, and every email and link in an answer looked invented.<\/li>\n<li>A heading with nothing under it is now indexed, so a contact page whose phone\nnumber is its heading has a chunk containing that number. Rebuild the index to\npick those up.<\/li>\n<li>Provider list trimmed to the ones whose terms and privacy policies can be\nlinked. Any other endpoint still works through \"Other\".<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>First release.<\/li>\n<\/ul>","raw_excerpt":"An AI chatbot that answers customer questions from your own posts and pages, and puts a citation under every answer.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/362665","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=362665"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/ibrahimhajjaj"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=362665"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=362665"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=362665"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=362665"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=362665"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=362665"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}