AI USE CASES YOU CAN REUSE.English edition · Individuals, independents, small businesses
PostHog

Migrating since customer change.io

migrating-from-customer-io

In brief

Move Customer.io automations to PostHog as a workflow. Read each automation with the client.io, K0, or CLI, preview the import with workflows-import-clientio (dry run), then import and guide the user through what needs their input. Use it to migrate, move, change, copy or import from Customer.io (client.io, IOC) to PostHog workflows, including "migrating everything to PostHog".

What it does

  • Never move people
  • Keep message content out of context
  • Steps

Who it is for, and an example

People whose task corresponds: Move Customer.io automations to PostHog as a workflow.

Example request: "Migrating from customer.io: Move Customer.io automations to PostHog as a workflow. »

Move Customer.io automations to PostHog as a workflow. Example written by iadujour.fr from the SKILL.md, not tested.

Install

Claude Code : /plugin marketplace add PostHog/skills, puis /plugin install posthog-all@posthog-skills (README).

/plugin marketplace add PostHog/skills
/plugin install posthog-all@posthog-skills

Works with

  • Claude Code

Source: K0: marketplace K1: K2: Other agents are not appointed.

Level: Intermediate

Supposes a project already in place at the publisher and the tools described in the K0.

Good to know

PostHog Official Deposit (github.com/PostHog/skills). Skills for product analytics, feature indicators, error tracking and team workflows.

SKILL.md excerpt

The original description, which the agent reads to decide whether to load the skill (in English):

Move Customer.io automations into PostHog as draft workflows. Read each automation with the Customer.io MCP or CLI, preview the import with workflows-import-customerio (dry_run), then import and walk the user through what needs their input. […]

Quoted from SKILL.md at commit 445764b .

The SKILL.md has 72 lines and 10 main sections:

  • Never move people
  • Keep message content out of your context
  • Steps
  • Reading the notes
  • Senders and categories
  • Images
  • Segments and cohorts
  • Push notifications
  • Re-running
  • After the import

Licence: MIT

Checked on 13 November 2026 : fichier de licence du dépôt.

The licence allows reuse: the full SKILL.md text is reproduced below, unmodified, with its licence notice.

Full SKILL.md text

Reproduced unmodified from PostHog/skills (commit 445764b) , © PostHog, under licence MIT (original licence file ).

Show the original SKILL.md (72 lines, in English)
---
name: migrating-from-customer-io
description: 'Move Customer.io automations into PostHog as draft workflows. Read each automation with the Customer.io MCP or CLI, preview the import with workflows-import-customerio (dry_run), then import and walk the user through what needs their input. Use when asked to migrate, move, switch, copy or import from Customer.io (customer.io, CIO) to PostHog workflows, including "migrate everything to PostHog".'
---

# Migrating from Customer.io

PostHog imports Customer.io automations as **draft workflows**. Drafts never send. A person reviews each one, fixes what the import could not carry over, and enables it.

You move the data between two MCP servers. Read from Customer.io's MCP (or the `cio` CLI), and pass what it returns **unchanged** to PostHog's `workflows-import-customerio`. PostHog does the translation, so do not rebuild workflows yourself with `workflows-create`.

## Never move people

Pass automations, templates, sender identities and segment names only. Never fetch or pass customer profiles, segment members, deliveries or event data. The people are usually in PostHog already, and copying them is a privacy risk the user did not ask for.

## Keep message content out of your context

Email templates are large, often tens of kilobytes of HTML each. When the PostHog project stored a Customer.io App API key (teams that ran the opt-out import have one), PostHog reads the message content from Customer.io itself. So pass the automation graph first, and read templates only if PostHog asks for them.

## Steps

1. **Confirm the PostHog project.** The drafts go into the PostHog MCP's active project. Read it with `project-get`, tell the user its name and id, and ask whether the drafts should go there. If not, switch with `switch-project` before you read anything from Customer.io.
2. **Find the environment.** Ask which Customer.io workspace to migrate if there is more than one. Its id is the `environment_id` in every path below.
3. **List the automations.** `GET /v1/environments/{environment_id}/campaigns` with the Customer.io read tool (`cio_read_api` on the MCP, `cio api` on the CLI). It returns 20 per page through `page` (0-based): read every page until one returns fewer than 20. Show the user the list with each automation's state, and ask which to move. Running automations are the usual answer; skip archived ones unless asked.
4. **Read each automation.** `GET /v1/environments/{environment_id}/campaigns/{campaign_id}`. Keep the response's `campaign` object and its **top-level** `actions` array. `campaign.actions` does not exist.
5. **Read senders and segments.** `GET /v1/environments/{environment_id}/identities?type=email` for `sender_identities` (`id`, `email`, `name`), and the segment list for `segments` (`id`, `name`, `type`). PostHog matches each email to the PostHog sender with the same address, and names the segments in its notes. For every dynamic segment the chosen automations check (in a trigger, entry filter, exit condition or branch), read its rules with `GET /v1/environments/{environment_id}/segments/{segment_id}` and add the `conditions` object to that segment's entry. Never read segment members.
6. **Preview without templates.** Call `workflows-import-customerio` with `source: "customerio"`, `dry_run: true`, `campaigns: [{campaign, actions}]`, `sender_identities` and `segments`. Up to 50 automations per call.
7. **Read templates only if needed.** Go by each automation's notes, not by `content_fetched` alone: `true` only means PostHog read some content, and one automation can still miss its messages. For every automation whose notes say message content was not part of the import, or that PostHog could not read its messages, read the template of every action that has a `template_id` with `GET /v1/environments/{environment_id}/templates/{template_id}`, keep the `template` object, and preview again with `campaigns: [{campaign, actions, templates}]`. Read templates one at a time: listing every template in the workspace times out on large ones. Tell the user that Import from Customer.io on the Workflows Opt-outs tab stores their App API key, which skips this step next time.
8. **Collect snippets and layouts.** If a note names a Customer.io snippet, or a template body you read contains `{{ snippets.name }}`, read the workspace snippets and pass them as `snippets` (`{name: content}`). When PostHog read the content itself, it read the snippets too, and a note names any it could not find. If a note names a layout, read `GET /v1/environments/{environment_id}/layouts/{layout_id}` and pass its `body` as `layouts` (`{layout_id: body}`).
9. **Report the preview.** For each automation, give its status and its notes, grouped by level (see below). Ask before importing anything with status `failed`; its `validation_errors` say why the draft would be rejected.
10. **Import.** Call again with `dry_run: false` and the same arguments. Share each draft's link (`/workflows/{workflow_id}`) and the `needs_input` notes again, since the team must handle those before enabling.

When you are unsure of an endpoint's parameters, ask for that one endpoint's schema (`cio_schema` with `resource.method`). A whole resource's schema costs tens of thousands of tokens.

## Reading the notes

| Level          | Meaning                                                                                                 | What to tell the user                         |
| -------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| `needs_input`  | The draft needs a setting only the team can give: an email sender, a trigger cohort, a branch condition | These block enabling. List them per workflow. |
| `approximated` | The step works differently in PostHog, for example a wait capped at 30 days                             | Worth a look before enabling.                 |
| `unsupported`  | The setting has no PostHog equivalent and was left out, for example an SMS step                         | Decide whether to rebuild it another way.     |

The same notes appear in the PostHog app on the imported workflow, and `workflows-import-notes` returns them for one workflow.

## Senders and categories

An email gets the PostHog email sender with the same address as its Customer.io sender. When no PostHog sender has that address, a `needs_input` note names it, so the user can add it as a sender. An email's subscription topic, or the automation's topic when the email has none, becomes the PostHog message category the opt-out import made from that topic. When the topics were not imported, a note says so.

## Images

The import copies email images hosted by Customer.io into the project's media library, so they keep loading after the Customer.io account closes. That needs the `uploaded_media:write` scope. If a note says images still load from Customer.io's servers, ask the user to reconnect the PostHog MCP and allow uploading media, then import again.

## Segments and cohorts

A real import turns each dynamic segment passed with its `conditions` into a realtime cohort, and uses it for that segment's triggers and conditions. The response's `segment_cohorts` says what happened to each segment: `would_create` in a preview, `created`, `reused` when an earlier import made the cohort, or `not_converted` with a `reason`. Tell the user which cohorts the import will create before importing for real.

A segment becomes a cohort only when every rule matches a cohort condition exactly: person attribute comparisons, such as equals, contains, exists, greater than and absolute dates. Rules on events, attribute changes, message activity, other segments, devices, relationships and relative dates ("in the last 30 days") have no exact match, so that segment is not converted and its automations get a `needs_input` note naming the rules. Creating cohorts needs the `cohort:write` scope and edit access to cohorts; the project also needs realtime cohorts and cohort triggers. When one is missing, the reason says which.

If the user already has a PostHog cohort that matches a segment, pass `segment_cohorts: {"<segment id>": <cohort id>}` and the import uses it instead of creating one. A cohort trigger needs a realtime cohort. A static segment gets its own note: workflows cannot check a static cohort, so the user rebuilds it as conditions. Static segment members are never imported.

## Push notifications

Push steps import as `unsupported` notes, and device tokens never move with the import. If the user sends push from Customer.io, tell them that a device reaches PostHog only when its app registers it with the PostHog SDK, or when they import their exported device tokens into a PostHog push channel. That token import is a separate step the user starts, because tokens are people data.

## Re-running

Importing an automation again replaces its draft, so you can re-run after fixing something in Customer.io. Edits the team made to that draft since are lost, so ask before you re-import. A workflow that someone already enabled, or that the user can't edit, is never changed: its result is `skipped`.

## After the import

Do not enable the drafts. Point the user at the `needs_input` notes, then hand over to the `building-workflows` skill for testing and enabling, which needs the user's explicit sign-off.
Source. Card written by iadujour.fr from: Frontmatter, sections and body of the deposit. Checked on 13 November 2026. PostHog/skills .

In the directory

Use cases and guides that share a theme, industry or tool with this skill.

SAME PUBLISHER

Other PostHog skills: DevOps and deployment

Whole category
PostHogDevOps and deployment

Add integration

instrument-integration

Add PostHog integration to your application.

Tools: Claude CodeLevel: Advancedupdated 12/11/2026
PostHogDevOps and deployment

LLM Call Management

managing-llm-prompts

Createlife, version, release and stream LLM prompts with PostHog fast management.

Tools: Claude CodeLevel: Advancedupdated 11/11/2026
PostHogDevOps and deployment

Signal Scout

signals-scout-general

Multi-product signal detector.

Tools: Claude CodeLevel: Intermediateupdated 03/11/2026
DISCUSSION

Comments.

A field note, a question, a precision on this skill? Comments are reviewed before publication.

Published comments

Loading comments…

    Leave a comment

    Moderation charter. Every comment is reviewed before publication. We refuse hate speech, insulting or discriminatory language, advertising, spam and promotional links, off-topic posts and other people’s personal data.