Shopify App Store Audit: Dead Privacy Policy Links avatar

Shopify App Store Audit: Dead Privacy Policy Links

Pricing

from $5.00 / 1,000 results

Go to Apify Store
Shopify App Store Audit: Dead Privacy Policy Links

Shopify App Store Audit: Dead Privacy Policy Links

Shopify requires every app to publish a privacy policy and never rechecks the link. This audits the links a listing declares: policies that 404, policies that redirect to a homepage, domains nobody has registered - anyone can publish there - and dead developer and documentation links.

Pricing

from $5.00 / 1,000 results

Rating

0.0

(0)

Developer

Ai-Q Labs

Ai-Q Labs

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

41 minutes ago

Last modified

Share

Shopify App Store Audit

Shopify requires every app in its App Store to publish a privacy policy, and shows the link on the listing. It never revisits it.

A merchant installing an app inherits whatever that policy says, and frequently cites it in their own store's privacy notice. So the link matters long after the developer typed it in — and nothing in the store checks whether it still leads to a policy.

This Actor checks. It reads the links each listing declares, follows every one of them, and asks the domain registry about the ones that failed.

The finding this exists for

A privacy policy URL whose domain nobody has registered.

That is not a broken link. It is an address anyone can move into: register the domain, publish a document, and the Shopify App Store will keep pointing every prospective merchant at your page, under the developer's name.

Two quieter versions of the same failure sit next to it:

  • The policy 404s. The requirement is unmet and the merchant has nothing to read.
  • The policy redirects to the site's front page. Every checker that stops at the status code reports a healthy 200. A reader following the link lands on a homepage. Google treats this shape as a soft 404; this Actor reports it by comparing the path asked for with the path landed on.

What comes out

One row per app, plus four key-value records:

RecordWhat is in it
dataset rowthe listing's facts, every declared link with its verdict, and the findings
ACTION_LISTfindings only, worst first, ranked by review count within a severity
PRIVACY_REPORTthe policies that are takeable, dead, or redirected to a homepage
DEVELOPER_PROFILESthe same findings grouped by developer, so a portfolio shows up as one
SUMMARYcounts, the query, the method, and every caveat that applies to the run

Input

Either name the apps or point at a category.

{
"apps": ["klaviyo-email-marketing", "https://apps.shopify.com/judgeme"],
"categories": ["store-design-site-optimization-seo"],
"pagesPerCategory": 2
}

An app is identified by its handle — the last segment of the listing URL. Full URLs are accepted and reduced to the handle.

What it will not do

It does not use the store's search. apps.shopify.com/robots.txt disallows any URL carrying q= for every user agent. Apps are discovered through category pages, which are permitted. A search URL passed in apps is refused with that reason rather than quietly stripped of its query. robots.txt is re-read at the start of every run, and the run stops if the listing pages stop being allowed.

It does not claim an app is abandoned. Shopify publishes a launch date and no update date. There is no honest way to get staleness out of that, so no finding is built on it. (The sibling Actors for the App Store and Google Play do make that call, because those stores publish the date.)

It does not call a refusal a death. A link answering 401, 403 or 429 is recorded as blocked at the lowest severity: the server is up and declining to talk to a program, which says nothing about whether a person clicking through reaches a page. Nothing here retries behind a browser user agent — being refused is an answer, and working around it would make this a different kind of tool.

It does not read review text, install counts, or anything behind a login. One request per listing page, one per declared link, and one per failed domain.

Severities, and why they sit where they do

Severity is chosen after measuring how common a condition is, never before. A warning that fires on healthy input erases the rows that say "nothing to report", which is the only reason the report is worth reading.

FindingSeverityWhy there
privacy_policy_domain_unregisteredcriticalanyone can publish a policy in the developer's name at the address Shopify still shows
declared_domain_unregisteredcriticalsame, for the developer's own website
privacy_policy_deadhighShopify requires a working policy; there is nothing to read or cite
developer_site_deadhighthe listing sends readers nowhere
privacy_policy_redirects_to_homepagemediuma 200 that is not a policy; needs a human to confirm the page moved
privacy_policy_not_listedmediumevery listing sampled had one, so this is a listing that dropped it or a change in the page
declared_link_server_errormedium5xx can be temporary — worth a second look, not a conclusion
resource_link_deadlowFAQ, tutorial and documentation links are not required
declared_link_blockedlowthe server is alive and refused us
declared_link_insecurelowonly when http:// stays http:// — a redirect to https costs the reader nothing
developer_site_offsitelowordinary after a rebrand, expected after a sale; the listing does not say which
app_not_foundcriticalthe handle is not on the store — removed, never published, or mistyped

Measured with this Actor's own code on 270 live listings in July 2026 — 86 from the top of six categories and 184 from pages 14–30 of seven, where the smaller and older apps sit. Every listing in both samples published a privacy policy. In the long tail, 1.1% of those policies were dead, 0.5% sat on a domain nobody had registered, 1.6% of developer websites were dead — and 85.9% of apps had nothing to report at all. The full set is in SUMMARY.method.baseRates.

One thing it cannot tell you

The IANA RDAP bootstrap lists about 1,200 TLDs, and several common ones — .io, .co, .jp, .ro — are not among them. There is no standard place to ask who holds something.io. When a link on such a domain is dead, this Actor says it is dead and records the registration as unknown, in the finding text as well as the field. It never assumes the domain is safely held, and it never calls it free.

Cost and courtesy

Free to run; you pay Apify only for the compute, which is small — this fetches pages and resolves names, it does not run a browser. Requests are paced with a fixed delay and capped concurrency, because these are ordinary page loads on someone else's server.

The User-Agent names this Actor and links to its page, so anyone reading their logs can see who called.

Verification

Unit tests pin the parsing and the judgement against fixed input. A separate live check runs against the real store, real websites and real RDAP before every release, because the two sibling Actors both shipped bugs that only real data could surface — a healthy site called dead because it answered 403, and an entire TLD called unregistered because the wrong RDAP server was asked.

npm test # unit
npm run test:live # against the live store, sites and registries