Skip to content

About

Audit, import, export and live-check Shopify URL redirects from a CSV. Catches loops, chains and conflicts before they reach your store. Zero dependencies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

shopify-redirect-manager

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.

Example

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.

Features

  • 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. import stops on audit errors unless you pass --force.
  • Dry run by default. srm import shows 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 check requests 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 missing Location header is reported with the exact URLs.
  • Exports what is in the store. srm export writes 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 and THROTTLED cost errors with exponential backoff, and paginates the whole urlRedirects connection.
  • Zero runtime dependencies. Node's built-in fetch only, nothing to audit in node_modules. 50 tests run with node --test.

Installation

npx shopify-redirect-manager --help
# or
npm install -g shopify-redirect-manager

Requires Node.js 18+.

Getting an access token (only for export and import)

audit and check run without a token.

  1. In your store admin: Settings → Apps and sales channels → Develop apps → Create an app.
  2. Under Configuration → Admin API integration, grant online store navigation read and write access (read_online_store_navigation and write_online_store_navigation).
  3. Install the app and copy the Admin API access token (shpat_...).
  4. Export it with your store domain:
export SHOPIFY_STORE_DOMAIN=my-store.myshopify.com
export SHOPIFY_ADMIN_ACCESS_TOKEN=shpat_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

If an import reports an access error, check that these two scopes are granted to the app.

Usage

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

The CSV

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/hoodie

Paths 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.

Typical migration

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.com

Run 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.

As a library

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();

What it does NOT do

  • 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-tote should go to /products/canvas-tote rather 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 path as a path, so the audit strips query strings and says so. The schema doesn't spell out how Shopify matches a query string, so run srm check to 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 urlRedirects list and are not compared. check will 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. check tests the --base URL you give it. Run it once per domain.

FAQ

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.

Related Shopify tools

  • 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.

Contributing

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

Roadmap

  • Update and delete commands, behind an explicit flag, for the conflicts the tool currently reports and leaves alone.
  • A --base list, so check can run against several domains in one pass.
  • A JSON report option for audit and check, for dashboards and CI annotations.

License

MIT © Ecom Swift LLC

Need help?

This project is maintained by Ecom Swift LLC, a Shopify Partner.


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.

About

Audit, import, export and live-check Shopify URL redirects from a CSV. Catches loops, chains and conflicts before they reach your store. Zero dependencies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages