How We Merged Two National Rescue Feeds Into One Deck and Left the Application With the Rescue
Adoptable dogs are scattered across individual rescue sites and two large national aggregators that duplicate each other heavily. Even once an adopter finds a listing, a raw listing tells them almost nothing about whether that dog suits their home, their working hours or their experience. We built a mobile app over a merged, de-duplicated feed from Petfinder and RescueGroups, with a lifestyle questionnaire driving the match, an AI-written compatibility explanation on every dog, moderation for user-submitted dogs, and the formal adoption application deliberately handed back to the rescue that holds it.
Samantha Dean came to us with a consumer adoption app and an unusually disciplined view of what it should not do. She was not trying to become the rescue. She was trying to fix the part of adoption that happens before anyone fills in a form: finding a dog that actually fits.
That constraint shaped the build more than any feature in the brief. It meant the product could be judged on match quality rather than on application volume, and it meant the rescues stayed in control of their own process.
Petfinder and RescueGroups both index rescues nationally, and a rescue listing on both appears twice to anyone searching across them. An adopter scrolling a combined feed meets the same dog repeatedly under slightly different names, photos and descriptions, with no way to tell it is one animal.
The deeper problem is that a listing describes a dog rather than a fit. Breed, age, weight and a paragraph written by a volunteer say nothing about whether this dog will cope with a ten-hour workday, a small apartment, a toddler, or a first-time owner. Adopters are left inferring suitability from photographs, which is how dogs end up returned.
And any app that inserts itself into the adoption process risks making things worse. Rescues have vetting procedures, home checks and their own application forms for good reasons, and a third-party app that intercepts the application replaces a process built on judgement with one built on conversion.
The interface people picture when they hear the brief is the card deck. The deck is the easy part. A swipe experience over a feed that shows the same dog three times is worse than no app, so the merge and the de-duplication went in first.
A Cron Puller With De-Duplication Underneath
Both APIs are pulled on a schedule through BullMQ and Redis and reconciled into one index. Matching records across two sources that describe the same animal differently is the hard part of this product, and it runs continuously rather than at import, because rescue listings change and disappear on their own timetable.
The Questionnaire as the Match Input
Onboarding captures lifestyle answers and hard filters before the adopter sees a single dog. Hard filters remove what cannot work at all, and the questionnaire drives the ordering of what remains, so the deck an adopter swipes is already shaped by their home rather than by recency.
An LLM Writeup, Behind an Adapter
Each dog detail carries a compatibility explanation generated against that adopter’s answers. We built it through a provider-agnostic adapter with GPT-4o-mini as the current model, because the AI layer in a consumer app is the component most likely to change on price or capability, and swapping it should be a configuration change rather than a rewrite.
The Application Stays With the Rescue
A right swipe favorites the dog and the detail view links out to the rescue’s own application. We recognised the pattern from other marketplaces that sit in front of a regulated or judgement-based process: intercepting the transaction wins short-term engagement and loses the supply side. The rescues keep their vetting, and the app keeps its role.
Moderation on Everything Users Submit
Users and admins can submit dogs that are not in either aggregator. Every one passes through admin moderation before entering the deck, because an unmoderated submission path on an adoption app is an opening for sellers.
Each module maps to a role and a function. The data layer feeds the deck everything it shows.
Petfinder and RescueGroups are external dependencies with their own rate limits, outages and schema decisions. The ingestion runs as scheduled BullMQ jobs against Redis so a failed pull retries without taking the deck down, and the app reads from the merged index rather than from either API directly. An adopter swiping during a Petfinder outage sees the index as of the last successful pull.
NestJS with TypeORM over PostgreSQL 16 carries the API, deployed on auto-scaling EC2 behind Caddy with CloudWatch and Sentry watching it. The mobile client is Expo-managed React Native, which keeps the iOS and Android builds on one codebase and one release cycle.
The LLM calls run asynchronously rather than on the swipe. Generating a compatibility writeup at the moment a card is opened would put a model latency in front of the most-used interaction in the app, so the writeups are produced and cached against the adopter profile ahead of the detail view.
An adopter answers a lifestyle questionnaire, sets hard filters, and swipes a deck drawn from both national aggregators plus moderated submissions, with duplicates already removed. Opening a dog shows a compatibility explanation written against their own answers, and applying takes them to the rescue that holds the dog.
Administrators moderate submissions, manage users, read a KPI dashboard, and configure both the subscription tiers and the LLM layer without a deployment.
The app is in build. These describe the system as designed rather than results in market, and this section needs rewriting with real figures once it has launched.
“Everyone who pitched me wanted to build the application flow, because that is where the money looks like it is. The rescues would have refused to work with us within a month. Leaving that alone was the decision the whole thing rests on.”
We have built the ingestion layer before, and we know it decides whether the rest of the app is worth using.
Start the conversation