---
title: Build an adapter
description: Turn one app's export into an OWLF document, as an npm package.
---

An adapter reads one app's export files and returns an OWLF document. It implements the `Adapter` contract from `@owlf/core`.

```ts
import type { Adapter } from "@owlf/core";

export const myApp: Adapter = {
  id: "my-app",
  name: "My App",
  platforms: ["ios", "android"],
  exportSteps: ["Open Settings > Export", "Save the ZIP and add it here"],
  accept: [".zip", "application/zip"],
  status: "verified",
  detect: async (files) => 0, // 0 = not this app, 1 = certain
  parse: async (files) => {
    /* return createDocument(myApp, { mood, sleep, entries, warnings }) */
  },
};
```

## Rules

- **Keep source values.** Raw mood, raw emotion names, tag groups. Consumers decide the mapping.
- **No target app.** An adapter never names or imports another app.
- **Mood scale** worst to best, `position` 0 = worst. Set [`valence`](/format/scales#mapping-to-another-scale) only when position misleads.
- **Local day first.** Never derive `date` from UTC. See [dates and time](/format/dates-and-time).
- **Count what is lost** with `countDropped`. Photos go in `media.photos`.
- **`detect` is cheap and never throws.** Read names and the first bytes with `file.head(n)`, never whole files.
- **Errors** throw `AdapterError` with `message`, `why` and a `fix` the person can act on.

Helpers for ZIP (iOS ZIP64 safe, ranged reads), CSV, dates, scales and PDF text live in `@owlf/adapter-utils`.

## Package layout

```txt
packages/adapters/my-app/
  package.json        # @owlf/adapter-my-app
  README.md           # export steps, format notes
  src/index.ts        # exports `myApp`
  src/index.test.ts   # conformance + app-specific behavior
  fixtures/           # synthetic export, same bytes-level format as the real one
```

Real exports never enter the repository. Fixtures use made-up content in the exact format of the real file. The full guide lives in the repository: [adding an adapter](https://github.com/mrzmyr/owlf/blob/main/docs/adding-an-adapter.md).
