---
title: "Offlinery Case Study"
canonical: https://wavect.io/case-studies/offlinery/
language: en
description: "Offlinery was a dating app built against swipe culture, matching nearby people who actually wanted to meet in person. iOS and Android. Wound down in 2025."
image: "https://wavect.io/img/general/bak/open_graph_preview.jpg"
---

[← All case studies](/case-studies/)

![Offlinery logo](/img/clients/bak/offlinery.png)

CASE STUDIES · 2024-2025

Offlinery

# Real-time, sub-second matching on hostile mobile OSes, built end-to-end.

Offlinery was a dating app built against swipe culture. A proprietary matching algorithm surfaced nearby people who actually wanted to meet in person. Shipped on iOS and Android. Wound down in 2025.

AI Fullstack Build 2024-2025 Wind Down

At a glance

Engagement Fullstack Build

Industry Mobile / Real-time Geo

Stage Pre-seed

Year 2024-2025

Stack

React Native / Expo NestJS TypeORM Typescript Firebase Sentry

Status Wind Down

Live [github.com/wavect/offlinery](https://github.com/wavect/offlinery)

## Overview

Offlinery was a dating app built against swipe culture. A proprietary matching algorithm surfaced nearby people who actually wanted to meet in person. Shipped on iOS and Android. Wound down in 2025.

## What's the challenge?

Surface the right nearby person inside a minutes-long window so a real-world approach actually happens. Two compounding constraints: a proprietary algorithm doing sub-second proximity and mutual-intent filtering, and reliability against iOS and Android killing background tasks the moment they lose interest.

## What call did we make?

### Continuous, accurate location, while the screen is locked.

> Getting continuous, accurate location from a locked phone is brutal. The OS shuts background processes down to save battery. The privacy model nags the user every time matching needs to fire. Stay accurate against an OS actively suppressing you, and keep the prompts honest enough that users still say yes.

## What We Did

Both phone OSes actively suppress real-time matching. We designed every layer around motion-driven triggers, smart deferral, and graceful degradation, fallback path ready before the OS pushes back. Proprietary proximity engine on PostGIS. React Native + Expo with hardened background geolocation, push, error tracking, i18n. NestJS + TypeORM backend with JWT, throttling, transactional email and Expo push. Full App Store and Play Store releases. Sub-second proximity on a moving phone, on hardware that didn’t want to cooperate.

## Outcomes

### Real-time - Proprietary Matching Engine
- **Category:** Scale

### Sub-second - Proximity Queries
- **Category:** Scale

Want outcomes like these on your build?

Fixed scope. Fixed deadline. Signed SoW.

[Get in touch](/contact/)

## On Reel

![In-app demo.](/img/yt/mNqTMDJxd-A.jpg?v=9a42d13ee9be) In-app demo.

## Selected Screens

![Offlinery screen 1](/img/case-studies/offlinery/001_hu_a987c7fb34c20161.webp)

![Offlinery screen 2](/img/case-studies/offlinery/002_hu_45ffadc04493dd16.webp)

![Offlinery screen 3](/img/case-studies/offlinery/003_hu_c2f7956f79790f80.webp)

![Offlinery screen 4](/img/case-studies/offlinery/004_hu_2957c12d699ae59c.webp)

![Offlinery screen 5](/img/case-studies/offlinery/005_hu_47be90ea2357aec6.webp)

![Offlinery screen 6](/img/case-studies/offlinery/006_hu_63b7b7dbb80cb777.webp)

![Offlinery screen 7](/img/case-studies/offlinery/007_hu_8eb3c450ae8da0a0.webp)

![Offlinery screen 8](/img/case-studies/offlinery/008_hu_ca9b7bbd14ca4f82.webp)

## Architecture & Flows

### Production infrastructure

Backend, Postgres+PostGIS, analytics and logs on Google Cloud. Waitlist on Vercel. Sentry for crash reporting, MailChimp for transactional mail.

The diagram illustrates a simplified high-level architecture and omits confidential implementation and security details.

### Match notification flow

```
sequenceDiagram
  autonumber
  participant U as User App
  participant API as NestJS API
  participant DB as PostGIS
  participant N as Expo Push
  U->>API: location heartbeat
  API->>DB: find nearby candidates
  DB-->>API: matches (geo + filters)
  API->>N: notify both users
  N-->>U: silent push
```

Heartbeat → proximity query → mutual push. Background geolocation drives the loop; the API stays stateless.

## What We Learned

Real-time in-person matching lives or dies on signals the OS actively kills. Half the work is algorithm, half is platform fight. Motion-driven triggers, smart deferral, graceful degradation, fallbacks when accuracy gets capped. On a moving phone, speed and resilience are the same problem.

## Tech Stack

- [React Native / Expo](https://expo.dev/)
- [NestJS](https://nestjs.com/)
- [TypeORM](https://typeorm.io/)
- [Typescript](https://www.typescriptlang.org/)
- [Firebase](https://firebase.google.com/)
- [Sentry](https://sentry.io/)

## Tags

- AI / Matching
- Real-time Geo
- Mobile App

## Links & Resources

[GitHub Repository](https://github.com/wavect/offlinery)

Related services

- [Mobile App Development](/services/mobile-apps/)
- [AI Agents & Products](/services/artificial-intelligence/)
- [Custom Software Development](/services/software-development/)

Client references and trademarks

Wavect publishes these case studies about its own work. Client names, logos and trademarks are the property of their respective owners and are used here to identify the work, not to imply any partnership, sponsorship or endorsement. Each case study describes Wavect's own contribution inside a larger effort, and other parties, including the client's own teams and other vendors, contributed to the results. Figures attributed to a client are that client's own reported numbers. Figures about our work come from our records as of the review date, and we provide evidence on request. Reviews are reproduced from the platform named on each card and link to their source. We do not publish the commercial terms of any engagement, and product screenshots remain the property of the client shown. If you are named here and want a correction, a change or a removal, write to us and we will act on it: [office@wavect.io](mailto:office@wavect.io)

### [PromptID](/case-studies/promptid/)

PromptID is an AI-native EdTech platform for employers and universities. It examines learners by analysing the train of thought, not by rewarding memorisation. …

## Structured Data

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@id": "https://wavect.io/#organization",
      "@type": [
        "Organization",
        "ProfessionalService",
        "LocalBusiness"
      ],
      "employee": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "founder": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "legalRepresentative": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "name": "Wavect GmbH",
      "subjectOf": {
        "@id": "https://wavect.io/verified-claims.json#dataset",
        "@type": "Dataset",
        "name": "Wavect verified publication claims",
        "url": "https://wavect.io/verified-claims.json"
      },
      "url": "https://wavect.io/"
    },
    {
      "@id": "https://wavect.io/team/kevin-riedl/#person",
      "@type": "Person",
      "jobTitle": "Managing Director",
      "name": "Kevin Riedl",
      "sameAs": [
        "https://www.wikidata.org/wiki/Q139796365",
        "https://www.linkedin.com/in/wsdt",
        "https://github.com/wsdt"
      ],
      "url": "https://wavect.io/team/kevin-riedl/",
      "worksFor": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      }
    },
    {
      "@id": "https://wavect.io/team/christof-jori/#person",
      "@type": "Person",
      "jobTitle": "Managing Director",
      "name": "Christof Jori",
      "sameAs": [
        "https://www.wikidata.org/wiki/Q139796367",
        "https://www.linkedin.com/in/jocr77/",
        "https://github.com/jo-chris"
      ],
      "url": "https://wavect.io/team/christof-jori/",
      "worksFor": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      }
    },
    {
      "@id": "https://wavect.io/#website",
      "@type": "WebSite",
      "inLanguage": [
        "en",
        "de",
        "es",
        "zh"
      ],
      "name": "Wavect",
      "potentialAction": {
        "@type": "SearchAction",
        "query-input": "required name=search_term_string",
        "target": {
          "@type": "EntryPoint",
          "urlTemplate": "https://wavect.io/search/?q={search_term_string}"
        }
      },
      "publisher": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      },
      "url": "https://wavect.io/"
    },
    {
      "@id": "https://wavect.io/case-studies/offlinery/#webpage",
      "@type": "WebPage",
      "dateModified": "2026-05-21",
      "inLanguage": "en",
      "isPartOf": {
        "@id": "https://wavect.io/#website",
        "@type": "WebSite"
      },
      "lastReviewed": "2026-05-21",
      "speakable": {
        "@type": "SpeakableSpecification",
        "cssSelector": [
          ".faq-question",
          ".faq-answer"
        ]
      },
      "url": "https://wavect.io/case-studies/offlinery/"
    }
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@id": "https://wavect.io/case-studies/offlinery/#case-study",
  "@type": "Article",
  "about": {
    "@id": "https://wavect.io/case-studies/offlinery/#project",
    "@type": "CreativeWork",
    "creator": {
      "@id": "https://wavect.io/#organization",
      "@type": [
        "Organization",
        "ProfessionalService",
        "LocalBusiness"
      ]
    },
    "dateCreated": "2024-01-01",
    "description": "Fullstack Build engagement",
    "funder": {
      "@type": "Organization",
      "name": "Offlinery"
    },
    "name": "Offlinery",
    "subjectOf": {
      "@id": "https://wavect.io/case-studies/offlinery/#case-study",
      "@type": "Article"
    },
    "url": "https://github.com/wavect/offlinery"
  },
  "abstract": "Surface the right nearby person inside a minutes-long window so a real-world approach actually happens. Two compounding constraints: a proprietary algorithm doing sub-second proximity and mutual-intent filtering, and reliability against iOS and Android killing background tasks the moment they lose interest.",
  "author": {
    "@id": "https://wavect.io/#organization",
    "@type": [
      "Organization",
      "ProfessionalService",
      "LocalBusiness"
    ]
  },
  "datePublished": "2024-01-01",
  "description": "Offlinery was a dating app built against swipe culture. A proprietary matching algorithm surfaced nearby people who actually wanted to meet in person. Shipped on iOS and Android. Wound down in 2025.",
  "headline": "Offlinery, Wavect Case Study",
  "image": "https://wavect.io/img/clients/bak/offlinery.png",
  "inLanguage": "en",
  "isPartOf": {
    "@type": "CollectionPage",
    "name": "Wavect Case Studies",
    "url": "https://wavect.io/case-studies/"
  },
  "keywords": "AI / Matching, Real-time Geo, Mobile App, React Native / Expo, NestJS, TypeORM, Typescript, Firebase, Sentry",
  "mainEntityOfPage": "https://wavect.io/case-studies/offlinery/",
  "mentions": [
    {
      "@type": "DefinedTerm",
      "name": "React Native / Expo",
      "url": "https://expo.dev/"
    },
    {
      "@type": "DefinedTerm",
      "name": "NestJS",
      "url": "https://nestjs.com/"
    },
    {
      "@type": "DefinedTerm",
      "name": "TypeORM",
      "url": "https://typeorm.io/"
    },
    {
      "@type": "DefinedTerm",
      "name": "Typescript",
      "url": "https://www.typescriptlang.org/"
    },
    {
      "@type": "DefinedTerm",
      "name": "Firebase",
      "url": "https://firebase.google.com/"
    },
    {
      "@type": "DefinedTerm",
      "name": "Sentry",
      "url": "https://sentry.io/"
    }
  ],
  "publisher": {
    "@id": "https://wavect.io/#organization",
    "@type": [
      "Organization",
      "ProfessionalService",
      "LocalBusiness"
    ]
  },
  "url": "https://wavect.io/case-studies/offlinery/",
  "video": [
    {
      "@id": "https://wavect.io/case-studies/offlinery/#video-mNqTMDJxd-A",
      "@type": "VideoObject",
      "description": "In-app demo.",
      "duration": "PT59S",
      "embedUrl": "https://www.youtube-nocookie.com/embed/mNqTMDJxd-A",
      "inLanguage": "en",
      "name": "Dating Apps are Out: Meet In Real Life Instead",
      "publisher": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      },
      "thumbnailUrl": "https://i.ytimg.com/vi/mNqTMDJxd-A/maxresdefault.jpg",
      "uploadDate": "2024-10-30T00:00:00+00:00",
      "url": "https://www.youtube.com/watch?v=mNqTMDJxd-A"
    }
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "item": "https://wavect.io/",
      "name": "Home",
      "position": 1
    },
    {
      "@type": "ListItem",
      "item": "https://wavect.io/case-studies/",
      "name": "Case Studies",
      "position": 2
    },
    {
      "@type": "ListItem",
      "item": "https://wavect.io/case-studies/offlinery/",
      "name": "Offlinery",
      "position": 3
    }
  ]
}
```
