Replace text in multiple Freshdesk articles
Freshdesk has no find and replace for solution articles, and the API has no bulk update. Three ways to change a name or link across every article, safely.
Updated
Freshdesk has no find and replace for solution articles, and its API has no bulk update endpoint. To change a name, price or link across many articles, you edit each one by hand, write a script against the API, or use a tool that previews, snapshots and can undo the batch.
This guide compares the three routes, shows a safe script sketch, and ends with a checklist for renames.
What Freshdesk's bulk actions can and can't do
In the knowledge base list view, Freshdesk lets you select several articles and act on them together: move them to another folder, change visibility, change the author, and manage tags. Advanced article bulk actions are a Pro and Enterprise feature.
None of those actions touch article text. The article editor has no replace function either; your browser's Ctrl+F only finds text on the screen.
The API has the same gap. There is an endpoint to update one article (PUT /api/v2/solutions/articles/[id]) and nothing to update many. When someone asked the Freshworks developer community about bulk updates, the answer was to use the UI.
- Knowledge base features by plan
- Freshdesk API v2 reference: Solutions
- Bulk update articles (Freshworks developer community)
Checked 2026-09-19 · Freshdesk docs, API reference and developer community
Option A: edit each article by hand
The default route. Search the knowledge base for the old term, open each result, find every occurrence, edit, and save.
Our estimate of the effort, with the arithmetic: about 2 minutes per article (open, find, edit title and body, check the SEO fields, save). 100 articles is roughly 3.3 hours. Each translation is a separate article, so 3 languages triples that.
What goes wrong:
- Missed places. Search finds the body text, but the old name also hides in titles, meta titles, meta descriptions, image alt text and link text.
- Missed variants. "Workspace", "workspace", "workspaces" and "Work space" all need a decision.
- No undo. If you replace something you shouldn't have, you fix it by hand again. Article versioning (Pro and Enterprise) lets you restore one article at a time.
Fine for 10 articles. Painful for 100. Not realistic for 400 in four languages.
Option B: an API script
If someone on your team writes code, the Freshdesk API can do the job one article at a time. Authentication is HTTP Basic with the API key as the username and X as the password. Lists return at most 100 items per page.
The endpoints you need:
| Step | Endpoint |
|---|---|
| List categories | GET /api/v2/solutions/categories |
| List folders in a category | GET /api/v2/solutions/categories/[id]/folders |
| List articles in a folder | GET /api/v2/solutions/folders/[id]/articles?per_page=100&page=N |
| Update an article | PUT /api/v2/solutions/articles/[id] |
| Update a translation | PUT /api/v2/solutions/articles/[id]/[language_code] |
Rate limits are per account, per minute, and shared with every other integration: 100 on Growth, 400 on Pro, 700 on Enterprise. Invalid requests count too.
A sketch in TypeScript (Node 22). It runs as a dry run unless you pass --apply, writes a JSON snapshot of each article before changing it, stays under half the Growth limit, and stops after 3 errors in a row. It only replaces text between HTML tags, so link URLs and attributes are left alone.
// replace.ts — dry run: npx tsx replace.ts · apply: npx tsx replace.ts --apply
// env: FD_DOMAIN=yourcompany FD_KEY=... FIND=Workspace REPLACE=Project
import { mkdir, writeFile } from 'node:fs/promises';
const { FD_DOMAIN, FD_KEY, FIND = '', REPLACE = '' } = process.env;
const APPLY = process.argv.includes('--apply');
const base = `https://${FD_DOMAIN}.freshdesk.com/api/v2`;
const auth = 'Basic ' + Buffer.from(`${FD_KEY}:X`).toString('base64');
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
const find = new RegExp(`\\b${FIND.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'g');
async function api(path: string, init: RequestInit = {}): Promise<any> {
await sleep(1200); // ~50 calls/min: half of Growth's 100/min
const res = await fetch(base + path, { ...init, headers: { Authorization: auth, 'Content-Type': 'application/json' } });
if (res.status === 429) {
await sleep(Number(res.headers.get('retry-after') ?? 60) * 1000);
return api(path, init);
}
if (!res.ok) throw new Error(`${init.method ?? 'GET'} ${path} → ${res.status}`);
return res.json();
}
async function pages(path: string): Promise<any[]> {
const out: any[] = [];
for (let page = 1; ; page++) {
const batch = await api(`${path}${path.includes('?') ? '&' : '?'}per_page=100&page=${page}`);
out.push(...batch);
if (batch.length < 100) return out;
}
}
// Replace only in text nodes, never inside tags (keeps href, src, alt untouched).
const replaceText = (html: string) => html.split(/(<[^>]+>)/).map((part) => (part.startsWith('<') ? part : part.replace(find, REPLACE))).join('');
await mkdir('snapshots', { recursive: true });
let errors = 0;
for (const category of await api('/solutions/categories')) {
for (const folder of await api(`/solutions/categories/${category.id}/folders`)) {
for (const article of await pages(`/solutions/folders/${folder.id}/articles`)) {
const title = article.title.replace(find, REPLACE);
const description = replaceText(article.description);
if (title === article.title && description === article.description) continue;
console.log(`${APPLY ? 'UPDATE' : 'would update'} ${article.id} ${article.title}`);
if (!APPLY) continue;
await writeFile(`snapshots/${article.id}.json`, JSON.stringify(article, null, 2));
try {
await api(`/solutions/articles/${article.id}`, { method: 'PUT', body: JSON.stringify({ title, description }) });
errors = 0;
} catch (e) {
console.error(e);
if (++errors >= 3) throw new Error('3 errors in a row, stopping');
}
}
}
}Why this is still risky:
- No preview for a person to approve. The dry run prints titles, not the changed sentences. Review the diff before
--apply, or you publish every match blind. - Drafts and status. Freshdesk's reference says that passing only
status: 1unpublishes an article. The sketch doesn't send a status, but test on one article first and check your portal before running on all of them. - Your snapshots are your only undo. The API has no versions endpoint. If the snapshot folder is lost, so is the way back. A restore script (PUT each snapshot's title and description) is worth writing before you apply.
- Translations are separate. The sketch covers primary articles only. Each language needs its own pass through the translation endpoint, with its own words to find.
- Nested folders and SEO fields. Accounts with subfolders (Enterprise) need to walk them too, and meta titles live in
seo_data. - Rate limits are shared. A long run can starve other integrations that use the same Freshdesk account.
Option C: TidyKB
TidyKB is built for this job: one search across titles, bodies and SEO fields, every match shown as a diff, and a batch you can undo.
In TidyKB
Bulk find and replace is being built for TidyKB's founding customers (target: 7 December 2026). It re-reads and compares each article immediately before writing, snapshots what Freshdesk returns afterwards, stops after 3 errors in a row, and restores a whole batch in one click. Freshdesk has no proven way to stage a draft beside a published article, so a change is written live rather than saved as a draft — the diff you approved and the snapshot are what protect you. Scans only read. See bulk find and replace for Freshdesk articles.
| By hand | API script | TidyKB | |
|---|---|---|---|
| Titles, bodies, SEO fields | One at a time | If you code it | One search |
| Preview before writing | You read each article | Only if you build it | Diff per match |
| Undo | Per article, versioning on Pro+ | Only from your snapshots | One click per batch |
| Translations | Each by hand | Separate pass | Choose languages in scope |
| Needs a developer | No | Yes | No |
The safety model is the same one the script above tries to copy. It is described on the security page.
Checklist before a rename
Go through this list before you replace a product or feature name across your help center.
- List every variant. Singular, plural, lowercase, hyphenated, abbreviations, and the old name inside URLs.
- Decide what stays. Release notes and changelog articles should often keep the old name, because they describe history.
- Check titles and SEO fields. Meta titles and descriptions are easy to forget and show up in search results.
- Check link text and image alt text. "See Workspace settings" is text; the URL behind it may also change.
- Plan for translations. Decide the new term per language before anyone translates, and add it to your glossary.
- Screenshots. Text changes won't fix a screenshot that still shows the old name. List those articles for a second pass.
- Links. If article URLs change with the title, update links that pointed at them. The guide on how to find broken links in Freshdesk covers this.
- Test with Freddy. If you use Freddy AI Agent, ask it three questions that mention the product by its new name.
Freshdesk and Freddy are trademarks of Freshworks Inc. TidyKB is an independent product and is not affiliated with, endorsed or sponsored by any company named on this page.
FAQ
Questions, answered
Is there a find and replace in the Freshdesk article editor?
No. The editor has no replace function, and the browser’s Ctrl+F only finds text on screen. Freshdesk’s bulk actions move articles and change visibility, author and tags, but never edit article text.
Can I bulk update articles with the Freshdesk API?
Not in one call. The API updates one article per request, with no bulk endpoint and no versions endpoint, so you need a script that pages through folders, respects your plan’s rate limit and keeps its own snapshots for undo.
Will replacing text break translations?
No, but it won’t update them either. Each translation is a separate article in Freshdesk, so changing the primary article leaves every language on the old text until you replace it there too and mark the translations outdated.
Related
- Find & replace Bulk find and replace across every Freshdesk solution article, with a diff preview, a snapshot of every article and one-click undo.
- How to find broken links in Freshdesk Freshdesk has no link checker. How links in solution articles break (archives, merges, URL changes), how to find them for free, and how to prevent them.
- Freshdesk API key: read-only, KB-only access Where to find your Freshdesk API key, and how to create a dedicated agent with a knowledge-base-only role so third-party tools can’t touch your tickets.
See your help center’s score.
Paste a URL. No signup, no API key, no call.