> ## Documentation Index
> Fetch the complete documentation index at: https://docs.therefrain.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Cross-App Data Sync

> Bridge two SaaS tools that lack API integration — extract from one, input into another.

## Overview

Many organizations use SaaS tools that don't integrate with each other. Without APIs, teams resort to manual copy-paste between systems — exporting from one tool, reformatting, and entering into another. This is slow, error-prone, and doesn't scale.

Refrain bridges this gap by chaining two runbooks: one to extract data from the source app, and another to input it into the destination app. No custom middleware or integration platform needed.

## Example runbook

**Step 1: Extract from source**

```yaml theme={null}
name: extract-from-crm
url: https://crm.example.com/contacts
variables:
  - name: username
    source: secrets
  - name: password
    source: secrets
steps:
  - action: input
    selector: "#email"
    value: "{{ username }}"
  - action: input
    selector: "#password"
    value: "{{ password }}"
  - action: click
    selector: "#login"
  - action: wait
    selector: ".contacts-table"
  - action: click
    selector: ".export-button"
  - action: download
    selector: ".download-csv"
```

**Step 2: Input into destination**

```yaml theme={null}
name: import-to-billing
url: https://billing.example.com/customers/new
variables:
  - name: company_name
    source: data
  - name: contact_email
    source: data
steps:
  - action: input
    selector: "#companyName"
    value: "{{ company_name }}"
  - action: input
    selector: "#contactEmail"
    value: "{{ contact_email }}"
  - action: click
    selector: "#create"
  - action: wait
    selector: ".success"
```

## Generate and execute

<Steps>
  <Step title="Generate the extract runbook">
    ```bash theme={null}
    npx @refrainai/cli generate -- \
      --url https://crm.example.com/contacts \
      --goal "Log in and export the contacts list as CSV" \
      --context ./context.md \
      --output ./extract-contacts.yaml
    ```
  </Step>

  <Step title="Generate the import runbook">
    ```bash theme={null}
    npx @refrainai/cli generate -- \
      --url https://billing.example.com/customers/new \
      --goal "Fill in the new customer form and submit" \
      --context ./context.md \
      --output ./import-customers.yaml
    ```
  </Step>

  <Step title="Run the sync">
    ```bash theme={null}
    npx @refrainai/cli execute -- \
      --runbook ./extract-contacts.yaml \
      --secrets ./secrets.json \
      --output-dir ./sync-data

    npx @refrainai/cli execute -- \
      --runbook ./import-customers.yaml \
      --data ./sync-data/contacts.csv
    ```
  </Step>
</Steps>

## Why this works well

* **No middleware** — Connect any two web apps without building custom integrations.
* **CSV as the bridge** — Extract outputs CSV, import consumes it. Simple and auditable.
* **Self-healing** — Both source and destination UI changes are handled automatically.
* **Approval gates** — Add human review before importing data into the destination.

## What's next

<CardGroup cols={2}>
  <Card title="Execute a runbook" icon="play" href="/guides/execute-runbook">
    Learn about chaining runbook executions.
  </Card>

  <Card title="Self-heal mode" icon="wrench" href="/guides/self-heal">
    Keep syncs running when UIs change.
  </Card>
</CardGroup>
