Skip to main content
SONZAI

From Character.AI / Replika

Migrate companion character chat exports from Character.AI, Replika, Chai, and similar companion apps into Sonzai. One character becomes one Sonzai agent; one user's conversation history becomes one Sonzai user.

What you're migrating

Character.AI, Replika, Chai, and similar companion apps don't expose public APIs for chat export. They do offer personal data download flows that return a zipped archive of your conversations, typically as JSON. The exact shape varies, but the logical units are the same:

Companion appSonzai
Character / botSonzai agent — create it separately, don't migrate it in here
Conversation (with one character)One chat_transcript block on the owning user
User (of the companion app)Sonzai user_id
Character persona / greetingAgent personality + bio — configure in Sonzai, not imported

This is a per-user migration, not a multi-tenant one. If you're a developer moving users off a companion product you built, you usually have your own user database and can do a batch import. If you're an individual moving your own chats into a Sonzai-powered app, a single-user prime is simpler.

Terms of Service

Check the source platform's ToS before exporting and reusing chat content at scale, especially on Character.AI and Replika where user-generated character scripts may be covered by the platform's terms. The code below assumes you have the right to move the data.

1. Export from the companion app

For most of these platforms you request a data download from settings and receive a zipped archive by email, usually within a few hours. Once unzipped, you're looking at one or more JSON files with a shape like:

[
  {
    "character_id": "luna",
    "conversation_id": "conv_abc",
    "created_at": "2025-11-20T09:12:00Z",
    "messages": [
      { "role": "user",       "content": "Hey Luna",     "created_at": "..." },
      { "role": "character",  "content": "Hi! Missed you.", "created_at": "..." }
    ]
  }
]

Different exports use different field names (role vs is_human, text vs content, bot_id vs character_id). Normalise to the shape above before running the import.

2. Map to Sonzai

For a single-user import (the most common case for companion apps):

import json, os
from sonzai import Sonzai

sonzai = Sonzai(api_key=os.environ["SONZAI_API_KEY"])
AGENT_ID = "agent_luna"   # the Sonzai agent that replaces the companion character
USER_ID  = "me"           # the individual migrating their own chats

def build_transcript(messages):
  lines = []
  for m in messages:
      role = "User" if m["role"] == "user" else "Agent"
      lines.append(f"{role}: {m['content']}")
  return "\n".join(lines)

def migrate_character_export(export_path: str, character_id: str):
  with open(export_path) as f:
      convos = json.load(f)

  # Only conversations with the character we're migrating to this Sonzai agent
  mine = [c for c in convos if c["character_id"] == character_id]
  mine.sort(key=lambda c: c["created_at"])

  content = []
  for c in mine:
      transcript = build_transcript(c["messages"])
      content.append({
          "type": "chat_transcript",
          "body": f"[conversation {c['conversation_id']} @ {c['created_at']}]\n{transcript}",
      })

  return sonzai.agents.priming.prime_user(
      AGENT_ID,
      USER_ID,
      source="character_ai",  # or "replika", "chai", etc.
      content=content,
  )

For a multi-user migration (you run the companion platform), pack each user into a batch_import entry the same way, using the platform's stable user ID as user_id.

3. Import and verify

curl -s https://api.sonz.ai/api/v1/agents/agent_luna/users/me/prime/$JOB_ID \
  -H "Authorization: Bearer $SONZAI_API_KEY" | jq '.status,.facts_stored'

# See what Sonzai extracted
curl -s "https://api.sonz.ai/api/v1/agents/agent_luna/memory/facts?user_id=me&limit=50" \
  -H "Authorization: Bearer $SONZAI_API_KEY" | jq '.facts[].content'

What moves, and what doesn't

Moves: your chat history, user identity (via user_id), and any user metadata you care to pass in (email, display_name, custom fields).

Doesn't move:

  • Character persona / backstory. Rebuild this on the Sonzai agent via personality config. Companion apps often bundle personality into freeform scripts; Sonzai uses Big Five personality + an explicit bio.
  • Character greetings / scenarios. Configure at agent level, not per user.
  • Character voice (Replika/Character.AI voice models). Sonzai ships its own TTS — see Voice.
  • Media attachments (images, voice notes, selfies). The import endpoints take text only. If media matters, store the URLs as text blocks ("Mia shared a photo of her hike: https://...") so the extractor at least records the reference.

Platform-specific notes

  • Character.AI exports group by character; filter to the character you're migrating.
  • Replika exports tend to have one long-running conversation per user with no character selection — use the whole history.
  • Chai exports are conversation-centric; treat each conversation as its own transcript block.
  • Janitor AI / others — if the export is raw JSON with messages, the shape-normalisation step is all you need.

What's next

  • Personality — rebuilding the character in Sonzai.
  • Voice — setting up TTS for the migrated character.
  • Custom JSON — if the export format doesn't match the examples here.

On this page