Audit, import, export and live-check Shopify URL redirects from a CSV. It catches loops, chains and conflicting targets before they reach your store, then confirms the redirects actually work on the live site. Zero dependencies.
We built this because every migration, theme rebuild or product cleanup ends with a spreadsheet of old URLs and new URLs, and the Admin API takes them one mutation at a time. Get one row wrong and a page quietly loops, or two rows fight over the same path. This checks the spreadsheet first, imports only what is missing, and then tests every redirect over HTTP so you are not relying on "it looked right in the admin."
Free audit for your own store while you're here: audit.ecomswiftllc.com checks SEO, speed, CRO and AI visibility in one pass.
Audit a file before you touch the store. examples/redirects-with-problems.csv is deliberately broken so you can see what gets caught:
$ srm audit examples/redirects-with-problems.csv
Audited 14 row(s): 11 importable, 5 error(s), 2 warning(s).
error line 3 "/products/tote" is mapped to two different targets (line 2 and line 3).
warning line 4 "/collections/summer" goes through /collections/summer-2026 before reaching /collections/summer-sale. Point it straight at /collections/summer-sale.
error line 6 "from" and "to" are the same path (/pages/faq). This would loop.
error line 7 "/pages/contact" eventually redirects back to itself. Fix the chain so it ends on a live page.
error line 8 "/pages/help" eventually redirects back to itself. Fix the chain so it ends on a live page.
error line 15 The "to" column is empty.
warning file 6 rows redirect to the homepage. Send each old page to its closest matching page where you can.
Exit code is 1, so the same command works as a CI gate.
After the import, srm check requests every old URL on the live site and reports each one that is not a permanent redirect to the expected page, with the exact URLs involved.
- Catches the mistakes that cause real damage. Self-redirects, loops (
A → B → A), loops that a chain runs into, two different targets for one path, and empty targets are all errors. Chains are warnings, with the final destination spelled out so you can point the row straight there. - Nothing is imported until it passes the audit.
importstops on audit errors unless you pass--force. - Dry run by default.
srm importshows what would be created, what already matches, and what conflicts with the store. Nothing changes until you add--apply. - Never overwrites what is already live. If a path already redirects somewhere else, it is listed as a conflict and left alone. You decide in the Shopify admin.
- Checks the live site.
srm checkrequests every old URL without following redirects and confirms the first hop: a permanent redirect to the right place passes, a 302 gets a warning, and a 200, 404, wrong target or missingLocationheader is reported with the exact URLs. - Exports what is in the store.
srm exportwrites every current redirect to CSV, so you can diff a migration against a backup or hand the list to someone else. - Built for real rate limits. Retries HTTP 429 (honouring
Retry-After), 5xx responses andTHROTTLEDcost errors with exponential backoff, and paginates the wholeurlRedirectsconnection. - Zero runtime dependencies. Node's built-in
fetchonly, nothing to audit innode_modules. 50 tests run withnode --test.
npx shopify-redirect-manager --help
# or
npm install -g shopify-redirect-managerRequires Node.js 18+.
audit and check run without a token.
- In your store admin: Settings → Apps and sales channels → Develop apps → Create an app.
- Under Configuration → Admin API integration, grant online store navigation read and write access (
read_online_store_navigationandwrite_online_store_navigation). - Install the app and copy the Admin API access token (
shpat_...). - Export it with your store domain:
export SHOPIFY_STORE_DOMAIN=my-store.myshopify.com
export SHOPIFY_ADMIN_ACCESS_TOKEN=shpat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxIf an import reports an access error, check that these two scopes are granted to the app.
srm audit <redirects.csv> Check a redirect CSV before importing it
srm export <out.csv> Save the store's existing redirects to CSV
srm import <redirects.csv> [--apply] Compare with the store, then create missing redirects
srm check <redirects.csv> --base <url> Request each old URL and confirm the live redirect
srm --help | --version
A header row with from and to (the aliases old_url and new_url also work), then one redirect per row:
from,to
/blogs/news/spring-sale,/blogs/news/spring-sale-2026
/products/old-canvas-tote,/products/canvas-tote
https://www.my-store.com/products/retired-hoodie,/products/hoodiePaths and full URLs both work. A full URL is reduced to its path, and its host is ignored because the redirect applies to your store's domain. A cross-domain move is the exception: a to on another host is kept as a full URL. examples/redirects.sample.csv is a working starting point.
srm audit redirects.csv # fix every error first
srm import redirects.csv # dry run: review the plan
srm import redirects.csv --apply # create what is missing
srm check redirects.csv --base https://www.my-store.comRun check after the import, not before. It tests the live site, so a redirect that was created but not yet active will show up there.
const fs = require('fs');
const {
parseRedirectCsv,
auditRedirects,
diffRedirects,
ShopifyGraphQLClient,
fetchAllRedirects,
createRedirects,
checkRedirects,
} = require('shopify-redirect-manager');
async function main() {
const { entries, error } = parseRedirectCsv(fs.readFileSync('redirects.csv', 'utf8'));
if (error) throw new Error(error);
const { issues, rules, summary } = auditRedirects(entries);
if (summary.errors) console.table(issues);
const client = new ShopifyGraphQLClient({
shop: process.env.SHOPIFY_STORE_DOMAIN,
accessToken: process.env.SHOPIFY_ADMIN_ACCESS_TOKEN,
});
const plan = diffRedirects(rules, await fetchAllRedirects(client));
await createRedirects(client, plan.create, { delayMs: 100 });
const results = await checkRedirects(rules, { base: 'https://www.my-store.com', concurrency: 3 });
console.log(results.filter((r) => r.result !== 'ok').length, 'redirect(s) need attention');
}
main();- Doesn't change or delete existing redirects. A path that already points somewhere else is reported as a conflict. Updating or removing it is a decision for you, in the admin or with your own code.
- Doesn't know your product or page inventory. It cannot tell that
/products/old-toteshould go to/products/canvas-toterather than the homepage. It checks the mapping you give it for structure, not whether the mapping is the right one. - Doesn't follow redirects past the first hop in
check. It confirms that each old URL redirects to the expected target. Two-step chains are caught in the audit, but a live chain that your CSV doesn't describe will not be traced. - Doesn't settle how Shopify treats query strings. The schema defines a redirect
pathas a path, so the audit strips query strings and says so. The schema doesn't spell out how Shopify matches a query string, so runsrm checkto see what your store does. - Doesn't cover redirects that live outside Shopify URL redirects. Redirects set by a theme, an app or a CDN rule are not in the
urlRedirectslist and are not compared.checkwill still see them over HTTP. - Doesn't retry a failed create for you. Each failed row is printed with Shopify's message. Fixing it and re-running the import is safe, because existing redirects are matched and skipped.
- Doesn't know about Shopify Markets or multiple storefront domains.
checktests the--baseURL you give it. Run it once per domain.
Why check the live site when the import already succeeded? A successful create only means Shopify accepted the row. The check confirms the redirect is served, lands on the right page, and is permanent (301 or 308) rather than temporary. That is the part that protects your rankings.
Why is a 302 only a warning? It works, and visitors land correctly. For a permanent move, search engines treat 301 as the stronger signal, so the check says so.
Will import overwrite redirects I already have?
No. Matching paths are either skipped (same target) or listed as conflicts (different target) and left as they are.
Can I use it in CI?
Yes. srm audit exits 1 on errors, and srm check exits 1 if any row is not ok. Put the audit on every pull request that touches the redirect file, and run check after each deploy.
Why a CSV and not a spreadsheet tool? A CSV is what every spreadsheet exports, and it diffs cleanly in git. Keeping the redirect map in version control is the easiest way to see who changed what.
If you're planning a migration and want someone to own the redirect map, the free store audit flags the pages most likely to lose traffic, and our free Shopify tools cover the rest of the checklist.
shopify-store-audit-toolkit— a CLI that crawls a live store for broken links, canonicals, robots directives and more. Good for finding the broken URLs that a redirect file should fix.shopify-seo-checklist— an interactive checklist, including the indexing and migration items this tool helps with.shopify-bulk-operations-toolkit— the Admin API Bulk Operations round trip, for when a redirect list is too large for synchronous mutations.shopify-order-export-cli— order export and revenue reporting, the other half of most migration checklists.shopify-ai-shopping-readiness— audits product structured data and AI crawler access, which should survive a URL migration.
Issues and pull requests are welcome, especially reports from stores where check gives a result that doesn't match what you see in a browser, and CSV files that the audit rejects but should accept.
npm test- Update and delete commands, behind an explicit flag, for the conflicts the tool currently reports and leaves alone.
- A
--baselist, socheckcan run against several domains in one pass. - A JSON report option for
auditandcheck, for dashboards and CI annotations.
MIT © Ecom Swift LLC
This project is maintained by Ecom Swift LLC, a Shopify Partner.
- 🛍️ Shopify Partner Directory: https://www.shopify.com/partners/directory/partner/waowy
- ✉️ Email: support@ecomswiftllc.com
- 💬 WhatsApp: https://wa.me/16312511767
Planning a migration or need the redirect map done properly? Get a free store audit (SEO, speed, CRO, AI visibility) or browse our other free Shopify tools. We're Ecom Swift LLC, a Shopify Partner Agency — www.ecomswiftllc.com.