Relief

How to check whether the apps you recommend still exist

Written for whoever maintains the resource page — a counselling centre, a library guide, a charity, a private practice. It takes about twenty minutes and needs no software you do not already have.

The problem is that nothing tells you

When an app closes, nobody writes to the pages that recommend it. There is no notification, no redirect, and no obligation on anyone to propagate the news. A page written carefully in 2022 quietly becomes wrong in 2025 and looks exactly the same.

Worse, the usual safeguards miss it. A broken-link checker tests whether a URL returns a page — and a withdrawn app’s App Store listing very often still returns a page. The failure only appears after somebody installs the app and cannot get in.

Three distinct things can go wrong, and they need different fixes:

What happenedWhat the link doesRight fix
Withdrawn — pulled from the store 404, or redirects to the store front pageRemove, or replace
Moved — republished under a new ID Old ID dead, app very much aliveRelink, do not delete
Closed but listed — service ended, listing left up Looks perfectly healthyRemove, and say why

The middle row is the one that causes real damage. Deleting a working app because its old link died removes a resource that people needed.

Step 1 — test every link against Apple’s own lookup

Every App Store URL contains a numeric ID, the part after id. Apple publishes a free lookup endpoint that needs no key and no account. If it returns "resultCount":0, the listing is not available.

curl -s "https://itunes.apple.com/lookup?id=1060691513&country=us"

To do a whole page at once, pull the IDs out of it first:

curl -s https://example.edu/counseling/apps.html \
  | grep -oE 'id[0-9]{6,}' | sort -u \
  | while read i; do
      n=$(curl -s "https://itunes.apple.com/lookup?${i/id/id=}&country=us" \
          | grep -o '"trackName":"[^"]*"' | head -1)
      echo "${i}  ${n:-*** NOT AVAILABLE ***}"
    done

Two things that will mislead you

Step 1b — do the same on Android, because an app can die on one platform only

This page checked Apple only for a long time, for the boring reason that Apple has a lookup API and Google does not. That was a real gap, and here is the case that exposed it.

On a university counselling page listing four apps, Breathe2Relax was alive on the App Store — current, published by the US Defense Health Agency — and its Google Play page returned 404. The iPhone link worked. The Android link did not. On the same page, two other apps were gone from both stores, and only checking both revealed which was which.

The split runs in the other direction too: on a school counselling page, an app’s Android listing had gone while its iPhone link still worked perfectly.

Neither is visible if you check on the phone you happen to be holding. And a page like yours is almost always checked on one device, by one person, once.

There is no API, so fetch the page and read the status — with a control package, exactly as you use a control ID on Apple:

curl -sL -o /dev/null -w '%{http_code}\n' \
  "https://play.google.com/store/apps/details?id=<package>"

The caveat, stated plainly, because this evidence is weaker than Apple’s. Google Play returns 404 for an app that is unavailable in your region as well as for one that has been removed. So a Play 404 is a strong signal, not a proof, and it is not as solid as resultCount:0 across five Apple storefronts. Where it matters, say “the Android listing does not load from here” rather than “the Android app is gone”.

Step 2 — check your PDFs, because nothing else does

This is the single most useful thing on this page. Handouts, printable guides and orientation packs are where dead links survive longest, because no link checker crawls a PDF, and because a printed copy cannot be corrected at all.

In one counselling-centre handout examined for this page, 11 of its 30 App Store links were dead. The same organisation’s website was in far better shape. The PDF had simply never been part of any check.

You do not need a PDF library to look. App Store links sit in the raw bytes as /URI entries:

curl -s https://example.edu/handout.pdf | strings | grep -oE 'https?://[^ )]*apple[^ )]*'

Step 3 — find every page that links a dead app

Once you know an ID is dead, search for the ID itself, in quotes, in any search engine:

"id825099621"

This works far better than searching the app’s name, because nobody writes an App Store ID anywhere except inside a link. One such search returned five separate institutions still linking the same withdrawn app.

A correction to what this page said before. It used to claim the search has “no false positives by construction”. That is wrong, and the reason is worth knowing.

The construction argument only holds if the index is current. It is often not. A search on one dead ID returned three institutional pages; none of the three actually contained it — one was unreadable, and the two that fetched cleanly had zero occurrences. The index was describing pages by content they had already removed. That has now happened six separate times during this work, on six unrelated queries.

So the rule is: treat every hit as a candidate to fetch, never as a confirmed carrier. Open the page and search it yourself before you write to anybody. The search is still the best way to find candidates — it just does not certify them.

The useful side-effect of the index lagging: some of those pages had already been fixed. That is worth knowing before you send a correction for something somebody dealt with last month.

If you run a large site, this is also the fastest way to audit yourself: add site:yourdomain.edu to the same query.

Step 4 — relink rather than delete, and mind the deadlines

The tidy reaction is to delete the entry. It is often the wrong one.

If the dead entry was free, check that the replacement still is

This is the trap waiting at the end of the job, and it is easy to walk into because the replacement genuinely was free once.

Looking for something to put in place of a closed free anxiety programme, the obvious candidates are the well-known university and health-service ones. One of them, THIS WAY UP, is excellent and widely cited. Its own page says the self-directed course is “$59 or covered by your private health insurance”, and free only “requires a prescription from a clinician”. Listing it under a heading that said “free” would have been wrong, and wrong in the direction that wastes a reader’s time when they are already struggling.

MoodGYM is the same shape of risk from the other direction: the phrase “freely available” appears on its site inside the title of a 2016 research paper. That is a citation, not a price. Its current terms could not be established from the public pages at all, so it is not listed here either.

The rule is short. A price is a fact about today, and reputation is not evidence of it. Read the provider’s own current pricing page before you write “free” next to anything — and if you cannot find one, say the cost is unclear rather than guessing in the generous direction.

Step 5 — the other links on the page, which are the ones that hurt

Steps 1 to 4 are about store links. A resource page is mostly not store links: it is charities, crisis directories, safety-plan tools, developer websites. Those fail differently, and worse, because the failures return 200.

Decode the URL before you request it

Take this one seriously, because getting it wrong causes the most damage of anything on this page.

An address written in HTML is not the address a browser sends. A URL with two parameters is written in the source with the ampersand escaped:

href="https://example.org/page.php?m=article&amp;ID=50966"

The browser requests it with a real &. A script that scrapes hrefs and feeds them to curl without decoding requests the literal string, and a site that ignores the malformed parameter will quietly serve you its homepage with a 200. Your report then says the link redirects to the site root — which reads exactly like a page that has been removed.

This happened during an audit written up for this site. The link flagged as broken was a university’s safety-planning tool. Requested correctly, it returns 200 and the page is titled “My Safety Plan”. It works. Acting on the uncaught version would have meant persuading a counselling service to delete a working safety plan on the strength of a report that looked rigorous.

So: decode entities before you request anything, and when a link appears to fall back to a homepage, open it in a browser before you write it down.

A 200 is not an arrival — compare the URL you got to the one you asked for

The status code tells you a server answered. It does not tell you it answered with the thing you asked for. Two shapes to watch, both real, both found on live institutional pages:

The check costs one flag. Ask curl what it actually reached:

curl -sL -o /dev/null -w '%{http_code}  %{url_effective}\n' "$URL"

If url_effective is a bare domain and you asked for a path, that is worth investigating — but do not report it until you have opened it in a browser, because there is one common case where it is completely wrong.

The exception, added after it nearly caused a 61-link false positive

Many library catalogues, repositories and databases route entirely on the client. The permalink is real, but the page that resolves it is JavaScript: the server returns the application shell, and the record is fetched afterwards. To curl this looks identical to a deep link collapsing to a homepage.

Auditing a college library’s health and wellbeing guide, every one of its 61 catalogue permalinks appeared to drop to the catalogue root. By the rule above, that is 61 broken links and an alarming email to a librarian. Opened in a browser, the first one resolved instantly to the right record — a different URL again, carrying the document id. Nothing was broken. Nothing had ever been broken.

So the rule needs its exception stated plainly: a drop to the root is a signal to look, not a finding. If it happens to one link on a page, it is probably real. If it happens to every link that shares a host, you have found a single-page application, not sixty-one faults — and the fastest way to tell the difference is to open one of them yourself.

Two smaller ones, from the same sweeps

Step 5 — check the developer’s website, not just the store link

Steps 1 to 4 check one link. Most resource pages carry a second one — the developer’s own site — and it fails in ways the store never shows you. Apple publishes that address as sellerUrl, which is also what the Developer Website button on the listing uses, so it comes out of the same lookup you already ran:

curl -s "https://itunes.apple.com/lookup?id=1019230398&country=us" \
  | grep -o '"sellerUrl":"[^"]*"'

Then fetch that exact address and look at where you land. Three failures show up here and nowhere else:

Two cautions, both learned the hard way while compiling the list. A 403 is not a dead site — it is the site refusing your script, and it belongs in your notes as unknown rather than broken. And a status code is a moment, not a fact: on this sweep one perfectly healthy site returned 504 on the first pass and 200 twenty minutes later. Re-check anything you are about to delete over.

Worked results for every app on the list, including which sites fail and which only look like they do, are on the checked list.

A worked example that trips every trap at once

Virtual Hope Box is a coping-skills app for service members and veterans, published by the US Defense Health Agency. It appears on a great many institutional resource pages under the ID 825099621. Checked on 26 August 2026:

LookupResult
id825099621&country=usnot available
id825099621&country=gbnot available
id825099621&country=canot available
id825099621&country=auavailable — last updated 8 November 2018
App Store search, “Virtual Hope Box” Virtual Hope Box (new), id6477622019, same publisher, updated 22 April 2026

Three separate lessons fall out of one app:

This is also why the search in step 3 matters. Every page still pointing at 825099621 is sending people to something withdrawn or eight years stale, and nobody has told any of them.

The “(new)” tell

Some publishers do not update an app. They publish a second one beside it and abandon the first, which leaves the old listing’s ID alive in every page that ever linked it while all the maintenance happens somewhere else.

You can often spot it in the app’s own name. Listing the US App Store catalogue of the Defense Health Agency on 26 August 2026 returns six apps, and three of them are named “(new)”:

Each of those names implies an older listing that pages are still pointing at, and these are among the most widely recommended apps on counselling, veteran and student resource pages.

Check a publisher’s whole catalogue in one request

Take the developer ID out of any apps.apple.com/…/developer/…/id… URL and ask the same endpoint for everything they publish:

curl -s "https://itunes.apple.com/lookup?id=1264687017&entity=software&limit=60&country=us"

If an app on your page is missing from that list, or appears there with “(new)” appended, your link is almost certainly the abandoned one.

Do this once per publisher rather than once per app. One agency, one request, and every app of theirs on your page is checked at once.

What this method cannot tell you

Who wrote this, and why that matters

I make Relief, a CBT thought record for iOS. That is a conflict of interest and it is the reason I started checking these pages at all, so you should know it before you use anything here.

The method itself does not care what the answer is, which is why it is worth publishing. It will tell you a competitor of mine is alive just as readily as it tells you one is dead, and several of the checks above exist specifically because I got the answer wrong the first time and had to correct it.

If you find an error in this, or you run it and get a result that does not make sense, write to me. I would rather fix it than be quoted saying something wrong.

Step 6 — check what the directory you link to is selling now

Every step so far has been about apps. This one is about the intermediaries: the curated app libraries that resource pages link to instead of listing apps themselves. They look like the safe option — somebody else does the vetting, and the link points at an organisation rather than at a store listing that might vanish. That is exactly why nobody re-checks them.

Here is what I found on one, on 27 August 2026.

my-therappy.co.uk is a UK app library for stroke, brain-injury and speech-and-language rehabilitation. It presents itself as clinician-assessed — its app pages carry a “Clinician Rating”, and the site describes testing by a network of NHS clinicians. The library is intact and still working: two dozen app pages, real write-ups, the aphasia and speech-therapy apps you would expect to find.

The site also now carries gambling affiliate sections. Its navigation links to pages titled Non UK Casinos, Non GamStop Casinos and Betting Sites Not on GamStop, and that navigation appears on the app pages too, alongside the clinician ratings.

And the front door is gone. Requesting the site root does not return a homepage at all — it issues a redirect to the casino page:

$ curl -sIL "https://www.my-therappy.co.uk/"
HTTP/2 301
location: https://www.my-therappy.co.uk/non-uk-casinos
HTTP/2 200

Every form goes the same way — with www or without, over http or https, with a trailing slash or without. The app library is still there at its deeper paths, so a link to a specific app or condition page still lands where it should. But anyone who linked the site itself — which is how most resource pages link a directory — is now sending readers straight to a page of casino offers.

A link checker sees 200 and moves on. So did I, at first: I fetched the root with redirects followed, saw casino promotions, and wrote it up as “the homepage carries gambling adverts.” It does not carry them. It is them — and I only found that out by printing the redirect chain instead of the final page. If you take one habit from this section, make it -I and -L together: where a link ends up is a different question from what it returns.

I am describing what the pages contain, not who put it there or why. A domain can change hands; a section can be added by an operator who needs revenue; none of that is knowable from outside. What is knowable is what a reader arriving from your page sees.

Why this is worse than a dead link. GamStop is the United Kingdom’s gambling self-exclusion scheme: someone who wants to stop registers once and is blocked across licensed operators. “Not on GamStop” is a category defined by that block not applying. The audience routed to a site like this through rehabilitation resource pages includes people recovering from stroke and brain injury — a population in which changes to impulse control are a recognised clinical consequence.

A dead link fails visibly and wastes somebody’s time. This one works perfectly.

What to actually do

Fetch the directories you link to, not only the apps, and read what is on them now — including the navigation, which is where this appeared rather than in the body text:

curl -sL "https://example.org/" | grep -oiE '>[^<]{0,40}(casino|betting|gambling|bonus)[^<]{0,40}<'

That grep is deliberately narrow, and the general version is simply to open the page. The point is not this keyword set. It is that an intermediary is a page like any other, and the reason it feels safe to link is the same reason nobody looks at it twice.

Step 7 — the address on the contact page is a claim too

Every step above ends the same way: you found something worth telling somebody, so you write to the address the site publishes. That address is the last unchecked assumption in the whole method, and I only noticed because two of mine bounced on the same night.

Both were published addresses. Neither was guessed. I have a standing rule against inventing a local part — info@, hello@, a name pattern copied from another site — because the local part is part of the identifier, and a guess that happens to land is worse than one that bounces. So I take the address off the site. That rule held. It just protects against the wrong failure.

The first one: the address is fine, the mailbox is gone

A Spanish site reviewing AI mental-health chatbots publishes one address on four separate pages, twice as a live mailto: link, next to the sentence that it tries to answer every message within 72 working hours. The domain runs its own mail server. The mail server answered:

550 Unrouteable address

There is no contact form anywhere on the site — I checked every page that could carry one, and the HTML contains no <form> element at all. So a site that invites editorial corrections, and promises a response time for them, currently has no channel that reaches a human. Nothing on the page says so. It reads exactly like a site you can write to.

The second one: the dead address is on the page that exists to catch the dead ends

A Brazilian startup publication publishes a contact address on /contato/, on /expediente/, and on its own 404 page — the page that asks you to write in when something on the site is broken. That address returned:

the email account that you tried to reach does not exist

And the two contact pages are themselves gone. /contato/ and /expediente/ both return 404, serving byte-for-byte the same page as a URL I invented to test it:

$ curl -sL -o /dev/null -w "%{http_code}\n" https://www.projetodraft.com/contato/
404
$ curl -sL -o /dev/null -w "%{http_code}\n" https://www.projetodraft.com/naoexiste-teste-404/
404

That is the whole failure in one shape: the escape hatch for broken things is itself the broken thing, and it is advertised on the page whose only job is to catch people when something breaks.

What an MX record does and does not prove

Both domains have working mail. The Spanish one runs its own server; the Brazilian one is on Google Workspace. A DNS check tells you the domain accepts mail. It tells you nothing about whether that mailbox exists, which is the only question you actually have:

dig +short MX example.com

So the check is worth thirty seconds as a negative signal — no MX at all means stop — and it is worthless as a positive one.

What to actually do

Two things, and the second is the one that recovers the contact.

Treat the bounce as data, not as an ending. A bounce is the only evidence that separates a published address from a working one, which makes it the most informative reply you can get. Read the server's actual words: 550 Unrouteable and account does not exist both mean the mailbox is gone, and neither means the organisation is.

When it bounces, go find another published address — do not start guessing. The temptation after a bounce is to try the obvious variants, and that is precisely the moment the rule matters most. On the Brazilian site, the page that still returns 200 is /quem-somos/, and it lists two named editors with their own addresses and an explicit invitation to write to them. The contact route was never missing. It had just moved off the page called “contact” and onto the page called “who we are”, and the site never updated the first to say so.

Which is the same lesson as Step 1, pointed at yourself. A name in a list is a claim about an app, and only the lookup settles it. An address on a contact page is a claim about a mailbox, and only a delivery attempt settles that. If you are going to hold other people's pages to that standard, the address you write to belongs inside it.

Step 8 — the app that still exists, and still cannot be had

Steps 1 to 7 catch two failures: the app was deleted, or the app was renamed. There is a third, it is the hardest of the three to see, and I only found it because I audited a list where every automated check passed.

An app converts from something you download to something your employer gives you. The company still exists. The store listing still exists. The link still resolves. The lookup still returns resultCount 1. The publisher is unchanged and the version is recent. And a reader who follows your recommendation still cannot use it.

Two of them on one list

A 2021 list of twenty apps for first responders, credited to a named clinician at a major hospital, still carries both of these.

Woebot. The iOS listing is live — id 1305375832, version 6.6.1, updated 17 December 2025. Everything a checker looks at is healthy. The App Store description opens like this:

Please note to download you’ll need an access code from your provider,
employer or other Woebot Health partner. If you do not have an access
code, you will not be able to use the app.

Woebot Health retired the direct-to-consumer app on 30 June 2025. On Google Play, com.woebot returns 404 while a control package returns 200 in the same run.

Happify. Renamed in place — the app is now Dario Mind (Twill), id 1593202787, still published by Happify, Inc., updated 1 July 2026. So Step 5's rename check finds it. What the rename check does not tell you is where the vendor's own front door now goes:

$ curl -sL -o /dev/null -w "%{url_effective}\n" https://www.happify.com/
https://happify.dariomind.com/?access_code=happify

An access code, in the URL, on the homepage.

Why nothing catches this

Every signal a link checker or a store lookup can read is positive. There is no 404, no resultCount 0, no publisher change, no stale version date. The only place the truth is written down is the prose of the store description, which is exactly the field that automated tools skip and human reviewers skim.

What to actually do

Read the first two hundred characters of the description. The lookup API already hands them to you, so this costs one command per app:

curl -s "https://itunes.apple.com/lookup?id=1305375832" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['results'][0]['description'][:300])"

Look for access code, through your employer, provided by your health plan, ask your provider, benefit, eligibility. Then follow the vendor's homepage with -L and see where it lands, which is the same habit Step 6 asks for and catches the Happify case in one line.

And when you find one, the fix is not deletion. The app is real and it may be genuinely available to some of your readers. Write down who can get it: “available through participating employers and health plans” is a true, short, useful sentence, and it is the difference between a recommendation and a dead end.

Somebody already does this properly

This is not a counsel of perfection, and it is worth naming an institution that got it right. When Ginger became Headspace Care, the HR department at UNC Charlotte published a page whose entire job is to say so — title and all: hr.charlotte.edu/ginger-now-headspace-care/. Not a quiet edit to a benefits list, but a standing page at a stable URL that answers the question an employee actually arrives with, which is “I was told to use Ginger and I cannot find Ginger”.

That is the cheapest possible fix and the most useful one: when a name changes, the old name needs somewhere to land. An employee searching your intranet for the word they were given should find a sentence, not silence.

The general form is worth stating plainly, because it now has three instances rather than one. A link that resolves is not a promise that a person can get in. Steps 1 to 5 test whether the thing exists; Step 6 tests what the page around it is selling; Step 7 tests whether you can reach the people responsible. This one tests something none of those do — whether the door is open to your reader specifically.

The failure mode that costs more than a wasted afternoon

Everything above assumes the worst outcome of a bad check is wasted effort. There is one case where it is worse than that, and it took me a while to meet it.

Search results are not evidence. I have now had eleven separate occasions where a search summary confidently described content that the page did not contain — across four countries and three top-level domains, so it is a property of indexes, not of any one site. Usually the cost is one wasted fetch.

Then this happened. Hunting for pages listing gambling-recovery apps, a result came back titled “Gambling Help & Support Resources — Ireland”, hosted at a path under a nail-salon domain. That is exactly the shape of a hijacked or repurposed site, and I had just spent five days documenting a real case of precisely that. Every prior of mine said I had found another one.

The page does not exist. The URL redirects to the site root, which is a nail salon — a real business, with a services list and an about page and no gambling content of any kind anywhere on it.

$ curl -sL -w "%{http_code}\n" https://rdsnailsandbeauty.org/ie/gambling-help/
301 → the homepage
$ grep -ic "casino\|betting\|gamstop" <the fetched page>
0

Had I trusted the snippet, the next step in my own process would have been to find a contact address and write to them about the gambling content on their site. To a nail salon. That is not a wasted email; that is an accusation, made to a real business, about something they did not do.

So the rule has a sharper edge than “fetch before you conclude”. It is this: the more damning a search result looks, the more it is costing you to believe it early. A snippet that says a page is boring will waste your time if it is wrong. A snippet that says a page is doing something wrong will spend your credibility, and somebody else's, if it is wrong. Fetch the page. Read what is actually on it. Then write.

Step 9 — the link names a storefront, and it may not be your reader’s

Every App Store URL contains a two-letter country code you probably never look at:

https://apps.apple.com/au/app/virtual-hope-box/id825099621
                        ↑
             this is a storefront, not decoration

Apple runs a separate storefront per country, and an app can be present in one and absent from another. So a link can be simultaneously working and useless: it returns a page, because the storefront it names still has the listing, while the storefront your readers actually shop in does not.

How I met it

A university counselling centre in New York State lists that exact URL under the heading Suicide prevention. Checking the ID one storefront at a time, against a control app queried in the same run:

id 825099621    au: 1    us: 0    gb: 0    ca: 0    ag: 0
control         au: 1    us: 1    gb: 1    ca: 1    ag: 1

The listing survives in Australia alone — which happens to be the single storefront the link names — and nowhere the students reading that page live. A link checker sees a healthy 200. So does a human who clicks it from the wrong country and gets redirected to a “not available” page they assume is a temporary glitch.

The app itself is perfectly fine. Its publisher, the Defense Health Agency, republished it under a new ID and a new title: Virtual Hope Box (new), id 6477622019. On Google Play the original package still resolves, so Android readers were never affected. I have since found the same retired ID on a second US university page, so it is not one librarian’s slip.

What to actually do

Two things, both cheap.

Read the country code in every store URL you publish. If your readers are in one country and the link says something else, fix it even when the link works — /us/ for a US audience, /gb/ for a UK one. A link that happens to work today because it points at Australia is working by accident.

Check the ID per storefront, not once. One lookup tells you an app exists somewhere. Your readers do not live in somewhere:

for cc in us gb ca au; do
  printf "%s: " "$cc"
  curl -s "https://itunes.apple.com/lookup?id=825099621&country=$cc" \
    | python3 -c "import sys,json; print(json.load(sys.stdin)['resultCount'])"
done

And the tell from earlier in this guide applies here too: when a publisher retires an ID and starts again, the new listing very often carries “(new)” in its title, because the old name is still taken. If a search for the app you meant turns up a result with that suffix, the ID you are linking is probably the dead one.

Step 10 — a dead ID and a wrong ID return the same zero

Every step above leans on the same command. You take the numeric ID out of an App Store link and ask Apple whether it still resolves:

curl -s "https://itunes.apple.com/lookup?id=1305375832&country=us"

A "resultCount": 0 looks like a verdict. It is not, and the reason is worth sitting with, because it is the one hole in this whole method.

Zero has two causes and they are indistinguishable. The app was withdrawn — or you have the wrong ID. A typo, a digit dropped in a copy-paste, an ID you found in a five-year-old blog post that was wrong when it was written. All of them return exactly the same zero, from exactly the same command, with no error and nothing to tell them apart.

When you pull the ID out of the page you are auditing, this rarely bites: whatever that link points at is the thing you are checking, right or wrong. It bites when you go looking for an ID — when the page names an app without linking it, and you go and find a number for it. Then the number is your claim, not theirs, and the zero you get back may be a fact about your typing.

Here is the trap fully sprung. I looked up an ID I believed to be Youper’s. Six storefronts, six zeros:

us 0   gb 0   ca 0   br 0   mx 0   in 0

Damning. Also worthless. Because there is no listing left anywhere, there is nothing to check the ID against — no trackName to compare, no publisher to match. I could not prove I had ever held Youper’s ID rather than a plausible-looking wrong one, so I could not honestly use those zeros as evidence of anything, and I dropped them.

The rule: an ID is only evidence once something has confirmed it is the right ID. A lookup that returns 1 proves its own ID — the name and publisher come back with it. A lookup that returns 0 proves nothing on its own, because the one thing that would have confirmed the ID is the listing that is missing.

So when the answer is zero, go and find a source that does not depend on the ID at all:

None of this makes the lookup useless. It makes it a prompt rather than a conclusion — the thing that tells you where to look, not the thing you quote. The difference matters most when you are about to tell somebody their page is wrong. Being right for a reason that does not hold is the same as being wrong, and it costs you the next correction too.

Step 11 — a broken link announces itself; a name does not

Every step so far assumes the failure is visible. A link 404s. A lookup returns zero. Somebody taps a thing and nothing happens, and at least they know something is wrong.

This step is about the failure that stays quiet.

Plenty of resource lists name apps without linking them — printed handouts, PDFs, pages written before anyone thought a store link would rot. A name is not a dead end. It is a search query you have handed the reader, and app-store names are not reserved. When an app leaves, its name does not leave with it.

So the reader searches, finds something with that name, and installs it. Nothing failed. There was no error to notice.

What the searches actually return

These are US App Store searches run on 27 August 2026, for names that appear on real institutional lists I have audited:

“Pacifica” — the name Sanvello used before its rebrand, and still the name on more than one college handout. The store returns:

Pacifica Christian OC        Pacifica Christian High School
Mes Assurances               Pacifica            (a French insurer)
Pacífica                    ADM, Agencia de Difusion M…

A high school app, an insurance app, and a Spanish-language media app. Not one result is a mental-health tool of any kind.

“Relax Melodies” — the sharpest case, because both halves go wrong at once:

BetterSleep: Relax and Sleep      BetterSleep Health, LLC     id 314498713
Relax Melodies - Sleep Sounds    汇杭 钟                     id 1569331495

The app the list meant is the first one — same ID as the original link, renamed to BetterSleep. The second carries the name the reader is searching for and belongs to a different publisher entirely. The name leads away from the app; the app survives only under a name the list does not have.

“Panic Relief” — the original, credited on one handout to a named psychiatrist, is gone. A different developer now publishes Panic Relief: Anxiety & Calm. “MoodTools” returns the real one alongside a separate The Mood Tools from an unrelated foundation.

And the cases where nothing goes wrong

This is not a universal law, and treating it as one would just be a new way to be wrong. Searching “Sanvello” surfaces no impostor — the name is simply vacant. Searching “Woebot” returns Woebot, correctly. Searching “Virtual Hope Box” returns the Defense Health Agency’s republished version, which is exactly what you want to happen.

So the collision is common enough to check for every time and not common enough to assume. Check; do not predict.

The check

Whenever an entry turns out to be dead, renamed, or unlinked, do one more thing before you write to anyone: search the name and read the publisher of what comes back. Not the name — the publisher. The name is the part that has already failed you.

curl -s "https://itunes.apple.com/search?term=pacifica&country=us&entity=software&limit=5"

Then ask the question that actually matters: if a reader typed this name in, what would they install?

A footnote worth more than the step

One of the documents I audited — a county mental-health board’s app list — opens with this line:

“Apps may share similar titles; the publisher is given here to distinguish from similarly-named apps.”

They had worked it out already, and built the defence into the document’s structure before I arrived to explain the problem. It is a good reminder that the people maintaining these lists are often thinking harder than the state of their links suggests — and that the useful thing to send them is evidence, not a lecture.