Uninstalling a Shopify app removes the app. It does not always remove what the app, or the person who set it up, put in the theme. Months later a storefront is still requesting a script from a vendor nobody pays, rendering a snippet that outputs nothing, and loading styles for a widget that no longer exists. Finding that code is straightforward. Proving it is safe to delete is the part that deserves care.

In short

  • Start from the public storefront, not the theme editor. The storefront shows what actually loads.
  • Search the theme for evidence, then prove each candidate is orphaned before touching it.
  • Remove on a duplicated theme, one change at a time, and walk the purchase path in a browser.
  • Keep the untouched backup theme until the change has survived a normal week of traffic.

Why code gets left behind

Apps reach a storefront in a few different ways, and they clean up differently. Code an app injects through Shopify’s own mechanisms, such as theme app extensions and app embeds, lives with the app and goes away when the app does. Code written directly into theme files does not. That includes older apps that edited theme.liquid on install, snippets a support agent asked the merchant to paste in, and assets uploaded by a contractor during a rush.

Shopify’s own theme performance guidance recommends auditing third-party scripts and removing the ones that are no longer used, and its theme app extension documentation explains why extension-based apps leave nothing behind. The leftover problem is concentrated in everything that predates or bypasses that model, which on a store that has been live for a few years is a meaningful amount of code.

Step 1: Start from the storefront, not the theme

Open the public storefront’s HTML for the homepage and a product page. Do not start in the code editor; a theme has hundreds of files and you will be reading Liquid for an afternoon without knowing what matters. The rendered HTML is smaller and it is the truth: it is exactly what shoppers receive.

From that HTML, build three short lists:

  • Third-party hosts referenced by <script> and <link> tags, excluding the store domain and Shopify’s CDN.
  • Inline markers: global variables, distinctive class names, data- attributes and comments that name a vendor.
  • Empty containers: elements with an app-specific id or class that render nothing visible.

Then open the Apps page in Shopify admin and compare. Every vendor present in the HTML and absent from the Apps page is a candidate. So is any vendor on both lists whose app embed is switched off in the theme editor but whose script still loads, because that means the script is coming from the theme rather than the embed.

App Audit produces the host list, recognized vendors and inline markers for a public storefront URL, with sanitized source paths, so step one takes a minute instead of an afternoon.

Step 2: Search the theme for the evidence

Now the theme. Duplicate the live theme first and work in the copy; even searching is safer when a stray keystroke cannot reach production. Use the code editor’s search or, better, pull the theme locally with Shopify CLI and search the whole directory.

Search for each candidate three ways:

  • The vendor name, in any casing.
  • The hostname you saw in the HTML.
  • Any distinctive identifier: a snippet name, a global variable, a class prefix.

Expect to find the results in a predictable set of places:

  • layout/theme.liquid, especially just before </head> and just before </body>, where most pasted scripts land.
  • snippets/, as a file named after the app, referenced by a {% render %} or older {% include %} tag somewhere else.
  • assets/, as JavaScript or CSS files the vendor uploaded, referenced with asset_url.
  • sections/ and templates/, where product-page apps often added a block or a conditional include.
  • config/settings_data.json, where app-specific settings and disabled block configuration accumulate.

Write down every file and line for every candidate before removing anything. A snippet referenced from three templates is a different removal from one referenced once.

Step 3: Prove it is orphaned

A candidate is not orphaned because the app is uninstalled. It is orphaned when nothing that still matters depends on it. Four checks, in order of cost:

  1. Nothing else references it. Search for the snippet name and the asset filename across the whole theme. A file included by another file that is still in use is not orphaned, however dead the vendor is.
  2. The vendor is really gone. Not on the Apps page, no active embed, no one on the team using its dashboard, no invoice. Ask the person who owns marketing, not only the person who owns the theme.
  3. The code does not do a second job. Some “app” snippets grew to hold unrelated things: a custom size chart, a tracking parameter, a fix for a layout bug. Read the snippet, not just its name.
  4. Removing it changes nothing a shopper needs. On the duplicated theme, remove the code, preview, and walk the purchase path in a browser with the console open: collection, product, add to cart, cart drawer, checkout entry, account login. Compare the network panel against the live theme; the only difference should be the requests you intended to remove.

Things that look orphaned but are not

Shopify’s own analytics and feature scripts load from the store domain or Shopify’s CDN and belong there. Consent management scripts often look unowned and are legally required. Theme framework files with vendor-like names are part of the theme. Scripts wrapped in conditions may only load for logged-in customers, specific markets or specific templates, so an absence on the homepage proves nothing. When unsure, leave it and write down why.

Step 4: Remove on a duplicate, one change at a time

The mechanics are simple and the discipline is the whole point.

  1. Duplicate the live theme and rename the copy so its purpose is unambiguous, including the date.
  2. Remove one candidate: the reference and the file it referenced, together.
  3. Preview the copy. Walk the purchase path. Check the console and the network panel.
  4. Publish the copy. Keep the previous live theme unpublished and untouched as the rollback.
  5. Wait. A normal week of traffic, including whatever the busiest weekday is.
  6. Repeat with the next candidate.

Removing everything in one publish feels efficient and destroys the only diagnostic you have. If something breaks after a six-item cleanup, the fastest fix is to roll back all six, and you have learned nothing about which one mattered.

Step 5: Record what you removed

Keep a short log: date, what was removed, which files, why it was believed orphaned, who approved it, and which theme is the rollback. It takes two minutes per change and it is what turns the next audit from archaeology into a diff.

Then watch the public footprint. If script count and third-party hosts are being recorded regularly, a cleanup shows up as a measurable drop and a regression shows up as an unexplained rise. The monitoring guide covers how to do that without turning it into a full-time job.

Where a public scan fits

A read-only scan of the public storefront covers step one: the hosts, the recognized vendors, the inline markers and where in the document they appear. That is the list you carry into the theme. It cannot read theme files, see the Apps page, execute JavaScript, or tell you whether a snippet is safe to delete. Those are steps two through four, and they need a human with access and a duplicated theme. The app audit checklist puts this whole process in the context of a wider review.