Matching animals with adopters has always been part intuition, part guesswork. An experienced shelter worker can look at a family's application, look at a dog's profile, and have a pretty good sense of whether it'll work. But that intuition lives in one person's head. It doesn't scale. It doesn't transfer when that person leaves. And it definitely doesn't help at 2 AM when you're scrolling through 40 applications trying to figure out which ones to prioritize.
We wanted to build something that could do the pattern-matching part — the part where you look at what an animal needs and what a person can offer and figure out how well they line up. Not to replace the human judgment. Just to surface the best candidates so your team isn't starting from scratch every time.
So we built a matching engine. And honestly, we're pretty proud of how it turned out.
The simple version
Here's what it does from a shelter worker's perspective: you open a pet's profile, click on the Matches tab, and you see a ranked list of adopters and fosters who might be a good fit. Each one has a score — Excellent, Good, Fair, or Low — along with a short summary of why the match works (or doesn't). You can also go the other direction: open an adopter's profile and see which available animals are the best fit for them.
The matching considers things like species preference, living situation, experience with animals, whether they have kids or other pets, the animal's temperament and medical needs, and a bunch of other factors pulled from your custom forms. It flags potential problems (reactive dog + household with small children, for example) and highlights strengths (experienced foster offering exactly the kind of environment a shy dog needs).
You can run a quick match that takes a few seconds, or a full match that takes a bit longer but gives you detailed explanations for each pairing. Either way, the results show up right in the profile page. No separate app, no export, no extra steps.
How we actually built it (for the nerds)
If you don't care about the technical stuff, skip this section. But if you're the kind of person who wants to know what's under the hood, here you go.
The system works in three layers.
Layer 1: Profile building. When a pet or a person's data changes, we build a compatibility profile — a text summary of what matters for matching purposes. For animals, this is deterministic: we pull species, breed, temperament, medical complexity, behavioral notes, and custom form fields into a structured format. For adopters and fosters, we use an LLM to synthesize their application answers into a summary of what they offer and what they're looking for. All of this runs through a PII redaction pipeline first — we strip emails, phone numbers, addresses, and names before anything leaves your database.
Layer 2: Embeddings and vector search. Each profile gets turned into a 512-dimensional vector using OpenAI's text-embedding-3-small model. These vectors live in your Postgres database using pgvector, indexed with HNSW for fast approximate nearest-neighbor retrieval. When you request matches, we do a cosine similarity search to find the closest vectors — basically, the profiles that are most semantically similar to each other. This is the "quick match" mode and it runs in a couple seconds even with thousands of profiles.
Layer 3: Guardrails and scoring. Raw similarity scores aren't enough. A high embedding similarity doesn't help if the adopter wants a cat and the animal is a dog. So we run five deterministic guardrails on top:
- Species mismatch — hard disqualify
- Children safety — if the animal has aggression flags and the household has kids, hard disqualify
- Other animals conflict — same logic for multi-pet households
- Foster capacity — if the foster is already at their limit, hard disqualify
- Size/environment — large breed + small apartment gets a soft penalty, not a disqualifier
The final score combines the cosine similarity, the guardrail multipliers, and a confidence factor based on how complete the data is. More complete profiles produce higher-confidence scores. The result is a ranked list that balances semantic compatibility with hard practical constraints.
For full matches (not quick), we also generate a natural-language explanation for each top candidate: what makes the match strong, what the concerns are, and what the shelter should consider. These are generated on-demand so they're always based on current data.
What it's not
It's not making decisions. It's surfacing suggestions. Your team still reviews every match and makes the call. The AI doesn't approve adoptions, it doesn't reject applicants, and it doesn't send anyone a message. It just takes the stack of possibilities and puts the most promising ones near the top.
It's also not creepy. We take privacy seriously. The matching engine never sees names, phone numbers, email addresses, or physical addresses. It works with compatibility-relevant information only: living situation, pet experience, what they're looking for, what the animal needs. The PII redaction runs three separate layers (field type exclusion, column deny lists, and regex content scanning) to make sure personal data stays out of the pipeline. And if your organization is in the EU, UK, or Switzerland, the feature is automatically disabled to comply with GDPR.
Setting it up
It's an opt-in feature. Go to Settings > AI, flip the toggle, and choose which custom form fields should be included in matching profiles. (We only use fields you explicitly enable — we don't just vacuum up everything.) Then hit "Generate Profiles" to build the initial batch. After that, profiles update automatically when data changes.
The whole thing runs on your existing PawPlacer account. No separate subscription, no per-match fees, no third-party integrations to configure.
Why we built it this way
We could have built something simpler — a rules engine that checks a few boxes and spits out a yes/no. But the reality of matching is that the best fits often aren't obvious. A family that looks mediocre on paper might be perfect for a specific animal because of some combination of experience, patience, and lifestyle that a checkbox system would never catch.
Vector embeddings let us capture that kind of nuance. The text profiles describe compatibility in natural language, and the embedding space puts similar descriptions close together — even when they use completely different words. An adopter who writes "I work from home and have a quiet house" ends up near an animal profile that says "needs a calm environment with a present owner," even though they share zero keywords.
The guardrails on top keep it grounded. Embeddings are good at fuzzy matching but bad at hard constraints. You can't let a high similarity score override the fact that someone wants a cat and this is a dog. So we layer deterministic rules where they matter and let the AI handle the judgment calls where it's actually useful.
Try it
If you're already on PawPlacer, go check it out. Settings > AI, enable matching, pick your fields, generate profiles. If you're not on PawPlacer yet, the free plan includes everything — matching, profiles, the whole thing. No catch.


