Mixpanel API 이벤트 import

Mixpanel API 이벤트 import

Mixpanel이 제공하는 이벤트 Import API(POST /import)는 서버에서 과거 이벤트를 대량으로 Mixpanel에 전송할 때 사용해요. 요청 본문에 이벤트 배치(batch)를 JSON 형태로 담아 보내면 되고, 요청당 최대 **2,000개 이벤트 / 10MB(압축 전)**까지 받아준답니다. 실시간 이벤트가 아닌 데이터 웨어하우스나 백필(backfill) 데이터를 밀어 넣을 때 특히 유용해요.

출처: 문서

본문

엔드포인트와 인증

이벤트 import는 {region} 자리(예: us, eu)에 해당 리전을 넣은 URL로 POST 요청을 보내요. Basic Auth 인증으로 Owner 또는 Admin 서비스 계정(Service Account)의 project_id, username, password가 필요해요. 또는 **프로젝트 토큰(Project Token)**을 Basic Auth의 username 값으로 넣고 비밀번호는 비워두는 방식도 지원해요. project_id를 지정하지 않으면 제공된 토큰으로 인증이 처리돼요.

요청 방식(Content-Type)은 application/json 또는 application/x-ndjson을 지원하고, 네트워크 전송량을 줄이려면 Content-Encoding: gzip으로 압축해서 보낼 수 있어요.

curl --request POST \
  --url https://{region}.mixpanel.com/import \
  --header 'Authorization: Basic ***' \
  --header 'Content-Type: application/json' \
  --data '
  [
    {
      "event": "<string>",
      "properties": {
        "time": 123,
        "distinct_id": "<string>",
        "$insert_id": "<string>"
      }
    }
  ]
  '

요청 파라미터

헤더(Header)

  • Authorization (string, required): 서비스 계정 인증 정보
  • Content-Type (enum, 기본 application/json): application/json, application/x-ndjson
  • Content-Encoding (enum): gzip

쿼리 파라미터(Query Parameters)

  • strict (enum, 기본 1): 1로 설정(권장)하면 배치를 검증하고, 실패한 이벤트별 오류를 반환해요. 0, 1
  • project_id (string, 기본 <YOUR_PROJECT_ID>, required): 서비스 계정 인증에 쓰는 Mixpanel 프로젝트 ID

본문(Body, application/json) — 최소 배열 길이 1

[
  {
    "event": "Signed up",
    "properties": {
      "time": 1618716477000,
      "distinct_id": "91304156-cafc-4673-a237-623d1129c801",
      "$insert_id": "29fc2962-6d9c-455d-95ad-95b84f09b9e4",
      "ip": "136.24.0.114",
      "Referred by": "Friend",
      "URL": "mixpanel.com/signup"
    }
  }
]

주요 필드 요구사항

  • event (required): 이벤트 이름. 데이터 웨어하우스에서 불러오는 경우 테이블 이름을 이벤트 이름으로 쓰는 걸 권장해요. 고유 이벤트 이름 수는 적게 유지하고, 가변적인 맥락은 프로퍼티로 분리하는 게 좋아요. 예) "Paid Signup"/"Free Signup" 대신 "Signup" 이벤트 + Account Type 프로퍼티("paid"/"free").
  • properties (required): 이벤트에 대한 모든 프로퍼티를 담은 JSON 객체. 웨어하우스 데이터라면 컬럼 이름을 프로퍼티 이름으로 권장해요.
  • properties.time (required): 이벤트 발생 시간. epoch 기준 초 또는 밀리초를 넣어요. 1971-01-01 이전이거나 서버 기준 1시간 이상 미래인 시간은 거부되고, 미래 시간은 수집 시 현재 시간으로 덮어써져요.
  • properties.distinct_id (required): 이벤트를 수행한 사용자 식별자. 고유 사용자, 퍼널, 리텐션, 코호트 등 행동 분석에 필수라 모든 이벤트에 지정해야 해요. 사용자가 없다면 빈 문자열로 설정하고, 미지정 시 요청의 IP로 해시해 계산해요. 00000000-0000-0000-0000-000000000000, anon, anonymous, nil, none, null, n/a, na, undefined, unknown, <nil>, 0, -1, true, false, [], {} 같은 값은 금지돼요.
  • properties.$insert_id (required): 이벤트 고유 ID로 중복 제거(deduplication)에 사용해요. (event, time, distinct_id, $insert_id) 값이 모두 동일한 이벤트는 중복으로 간주돼 쿼리에 하나만 노출돼요. 36바이트 이하, 영숫자 또는 -만 허용돼요.

고수준 요구사항(High-level requirements)

  • 각 이벤트는 올바른 형식의 JSON이어야 해요.
  • 각 이벤트는 event, time, distinct_id, $insert_id를 반드시 포함해야 해요(안전한 재시도를 위해 필요).
  • 각 이벤트는 압축 전 1MB 미만이어야 해요.
  • 각 이벤트는 255개 미만의 프로퍼티를 가져야 해요.
  • 중첩 객체 프로퍼티는 255개 미만의 키와 최대 중첩 깊이 3을 가져야 해요.
  • 배열 프로퍼티는 255개 미만의 요소를 가져야 해요.

strict 검증과 오류 응답

strict=1(권장)이면 이벤트를 검증하고, 일부만 실패해도 400을 반환하며 통과한 이벤트는 수집해요. 실패 이벤트의 $insert_id가 응답에 포함되므로 운영 중 400 오류가 나면 JSON 응답을 그대로 로깅해 디버깅에 활용하면 돼요.

성공 응답 (200)

{
  "code": 200,
  "num_records_imported": 2000,
  "status": "OK"
}

검증 오류 응답 (400)

{
  "code": 400,
  "num_records_imported": 999,
  "status": "Bad Request",
  "failed_records": [
    {
      "index": 0,
      "insert_id": "13c0b661-f48b-51cd-ba54-97c5999169c0",
      "field": "properties.time",
      "message": "'properties.time' is invalid: must be specified as seconds since epoch"
    }
  ]
}

그 외 오류 코드: 401(잘못된 자격 증명), 413(요청이 2,097,152바이트 제한 초과), 429(프로젝트 속도 제한 초과 — 지수 백오프로 재시도).

GeoIP 보강(Enrichment)

ip 프로퍼티에 IP 주소를 넣으면 Mixpanel이 자동으로 GeoIP 조회를 해서 ip를 도시/지역/국가 등의 지리 프로퍼티($city, $region, mp_country_code)로 교체해줘요. ip를 넣지 않으면 요청 IP로 지오로케이션을 파싱하고, ip0으로 설정하면 해당 이벤트의 지오로케이션 파싱을 건너뛰어요.

속도 제한(Rate Limit)과 대량 전송 팁

  • 제한: 압축 전 2GB/분 또는 약 3만 이벤트/초(1분 롤링 기준).
  • 1020개 동시 클라이언트로 배치당 2K 이벤트씩 빠르게 보내고, 429가 나면 지수 백오프 + 지터(시작 2초, 60초까지 두 배로, 지터 15초) 전략을 쓰는 게 가장 좋은 결과를 보여요.
  • gzip 압축(Content-Encoding: gzip)으로 전송량과 시간을 줄이는 걸 권장해요.
  • 502/503도 429와 같은 지수 백오프 전략을 권장해요.
  • 검증 오류(400)는 계속 실패하고 속도 제한에 포함되므로 재시도하지 마세요.
  • $insert_id가 모든 이벤트에 필수라 /import 재시도가 안전해요. 고유 ID가 없다면 이벤트를 의미상 고유하게 만드는 일부 프로퍼티(예: distinct_id + timestamp + 기타 프로퍼티)의 해시 앞 36자를 $insert_id로 쓰는 걸 권장해요.
  • 모든 문자열은 255자로 잘려요. 긴 URL은 파싱해 host/path/파라미터를 프로퍼티로 분해하거나, JSON 문자열은 파싱해 평탄화(flatten)해서 보내는 게 분석에 유용해요.

사용 예시

Python (requests)

import requests

url = "https://{region}.mixpanel.com/import"

payload = [
  {
    "event": "<string>",
    "properties": {
      "time": 123,
      "distinct_id": "<string>",
      "$insert_id": "<string>"
    }
  }
]
headers = {
  "Authorization": "Basic <encoded-value>",
  "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)

JavaScript (fetch)

const options = {
  method: 'POST',
  headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
  body: JSON.stringify([
    {
      event: '<string>',
      properties: {time: 123, distinct_id: '<string>', $insert_id: '<string>'}
    }
  ])
};

fetch('https://{region}.mixpanel.com/import', options)
  .then(res => res.json())
  .then(res => console.log(res))
  .catch(err => console.error(err));

더 알아보기 (Learn more)