Repository navigation
feat!: remove the /batch fallback from capture V1 - #940
Conversation
59a43fd to
b7e06b5
Compare
posthog-ios Compliance ReportDate: 2026-10-27T19:05:47.249327+00:00
|
| Test | Status | Duration |
|---|---|---|
| Endpoint And Method.Targets V1 Endpoint | ✅ | 3078ms |
| Endpoint And Method.Does Not Use Legacy Endpoints | ✅ | 2691ms |
| Required Headers.Has Authorization Bearer Header | ✅ | 2882ms |
| Required Headers.Has Content Type Json | ✅ | 2728ms |
| Required Headers.Has Posthog Sdk Info Format | ✅ | 2773ms |
| Required Headers.Has Posthog Attempt Header | ✅ | 2776ms |
| Required Headers.Has Posthog Request Id | ✅ | 2841ms |
| Required Headers.Has Posthog Request Timestamp | ✅ | 2928ms |
| Required Headers.Has User Agent | ✅ | 692ms |
| Body Format.Body Has Created At And Batch | ✅ | 2755ms |
| Body Format.No Api Key In Body | ✅ | 2827ms |
| Body Format.No Sent At In Body | ✅ | 2807ms |
| Event Format.Event Has Required Root Fields | ✅ | 2972ms |
| Event Format.Event Uuid Is Valid | ✅ | 2985ms |
| Event Format.Event Timestamp Is Rfc3339 | ✅ | 3127ms |
| Event Format.Non Utc Event Timestamp Is Converted To Utc | ✅ | 2765ms |
| Event Format.Distinct Id Is String | ✅ | 2805ms |
| Event Format.Distinct Id At Root Not Properties | ✅ | 2774ms |
| Event Format.Custom Properties Preserved | ✅ | 2879ms |
| Event Format.Set Properties Preserved | ✅ | 2851ms |
| Event Format.Set Once Properties Preserved | ✅ | 433ms |
| Event Format.Groups Properties Preserved | ✅ | 2777ms |
| Event Format.Sdk Generates Uuid If Not Provided | ✅ | 2804ms |
| Event Format.Event Has Required Root Fields Batch | ✅ | 2900ms |
| Event Format.Event Uuid Is Valid Batch | ✅ | 2963ms |
| Event Format.Event Timestamp Is Rfc3339 Batch | ✅ | 2903ms |
| Event Format.Distinct Id Is String Batch | ✅ | 2869ms |
| Event Format.Distinct Id At Root Not Properties Batch | ✅ | 3037ms |
| Event Format.Custom Properties Preserved Batch | ✅ | 3175ms |
| Event Format.Set Properties Preserved Batch | ✅ | 549ms |
| Event Format.Set Once Properties Preserved Batch | ✅ | 499ms |
| Event Format.Groups Properties Preserved Batch | ✅ | 2960ms |
| Event Format.Sdk Generates Uuid If Not Provided Batch | ✅ | 3131ms |
| Batch Behavior.Multiple Events In Single Batch | ✅ | 3079ms |
| Batch Behavior.Batch Envelope Smoke | ✅ | 2918ms |
| Batch Behavior.Flush With No Events Sends Nothing | ✅ | 309ms |
| Batch Behavior.Flush At Triggers Batch | ✅ | 1284ms |
| Batch Behavior.Created At Reflects Batch Creation Time | ✅ | 2824ms |
| Deduplication.Generates Unique Uuids | ✅ | 3169ms |
| Deduplication.Different Events Same Content Different Uuids | ✅ | 3514ms |
| Deduplication.Preserves Uuid On Retry | ✅ | 9389ms |
| Deduplication.Preserves Timestamp On Retry | ✅ | 9282ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ✅ | 7890ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 2848ms |
| Header Behavior On Retry.Attempt Header Starts At One | ✅ | 2835ms |
| Header Behavior On Retry.Attempt Header Increments On Retry | ✅ | 15721ms |
| Header Behavior On Retry.Request Id Preserved On Retry | ✅ | 9325ms |
| Header Behavior On Retry.Different Requests Have Different Request Ids | ✅ | 7497ms |
| Header Behavior On Retry.Request Timestamp Changes On Retry | ✅ | 9239ms |
| Response Format Validation.Success Response Has Uuid Keyed Results | ✅ | 2763ms |
| Response Format Validation.Success Response Has Ok For Each Event | ✅ | 2861ms |
| Response Format Validation.Success No Retry After When All Ok | ✅ | 2873ms |
| Response Format Validation.Success Retry After Present When Retry Events | ✅ | 2900ms |
| Response Format Validation.Success No Retry After When Drop Only | ✅ | 2972ms |
| Response Format Validation.Response Echoes Request Id | ✅ | 2837ms |
| Retry Behavior.Retries On 408 | ✅ | 9225ms |
| Retry Behavior.Retries On 500 | ✅ | 9135ms |
| Retry Behavior.Retries On 503 | ✅ | 11829ms |
| Retry Behavior.Retries On 504 | ✅ | 9364ms |
| Retry Behavior.Retryable Errors Have Retry After | ✅ | 6234ms |
| Retry Behavior.Respects Retry After On Retryable Error | ✅ | 10864ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 2461ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 4768ms |
| Retry Behavior.Does Not Retry On 402 | ✅ | 4764ms |
| Retry Behavior.Does Not Retry On 413 | ✅ | 4734ms |
| Retry Behavior.Does Not Retry On 415 | ✅ | 4806ms |
| Retry Behavior.Non Retryable Errors Have No Retry After | ✅ | 4694ms |
| Retry Behavior.Implements Backoff | ✅ | 21810ms |
| Retry Behavior.Max Retries Respected | ❌ | 19235ms |
| Partial Batch Handling.Handles 200 Full Success | ✅ | 2361ms |
| Partial Batch Handling.Handles 200 With All Ok | ✅ | 5924ms |
| Partial Batch Handling.Does Not Retry Dropped Events | ✅ | 5723ms |
| Partial Batch Handling.Does Not Retry Limited Events | ✅ | 5878ms |
| Partial Batch Handling.Prunes Ok Events On Partial Retry | ✅ | 7825ms |
| Partial Batch Handling.Prunes Dropped Events On Partial Retry | ✅ | 7775ms |
| Partial Batch Handling.Retries Only Retry Events From Partial | ✅ | 7834ms |
| Partial Batch Handling.Partial Retry Preserves Uuids | ✅ | 7800ms |
| Partial Batch Handling.Partial Retry Attempt Header Increments | ✅ | 7872ms |
| Partial Batch Handling.Partial Retry Request Id Preserved | ✅ | 7814ms |
| Partial Batch Handling.Respects Retry After On Partial | ✅ | 7930ms |
| Partial Batch Handling.Unknown Result Treated As Terminal | ✅ | 5885ms |
| Partial Batch Handling.Mixed Ok Drop Limited No Retry | ✅ | 5992ms |
| Compression.Sends Gzip Content Encoding | ✅ | 2800ms |
| Compression.No Content Encoding When Disabled | ✅ | 2836ms |
| Compression.Compressed Body Is Decompressible | ✅ | 2784ms |
| Error Handling.Does Not Retry On Unknown 4Xx | ✅ | 2427ms |
| Event Options.Cookieless Mode Override | ✅ | 2810ms |
| Event Options.Disable Skew Correction Override | ✅ | 2774ms |
| Event Options.Process Person Profile Override | ✅ | 2833ms |
| Event Options.Product Tour Id Override | ✅ | 2849ms |
| Event Options.Unset Options Omitted | ✅ | 2773ms |
| Event Options.Options Override In Batch | ✅ | 2896ms |
| Event Options.Unknown Option Passes Through | ✅ | 2690ms |
| Event Options.Option Value Is Not Converted | ✅ | 2736ms |
| Event Options.Lenient Bool Option Values Are Not Converted | ✅ | 2779ms |
| Event Options.Option Wins Over Legacy Property | ✅ | 344ms |
| Event Options.Legacy Property Fills Unset Option | ✅ | 2834ms |
| Event Options.Null Option Falls Back To Legacy Property | ✅ | 2830ms |
| Geoip And Historical Migration.Geoip Disable Injected Into Properties | ✅ | 368ms |
| Geoip And Historical Migration.Historical Migration Set In Body | ❌ | 2772ms |
| Geoip And Historical Migration.Historical Migration Absent By Default | ✅ | 2772ms |
Failures
retry_behavior.max_retries_respected
Expected 4 requests, got 5
geoip_and_historical_migration.historical_migration_set_in_body
Body missing 'historical_migration' field. Body keys: ['batch', 'created_at']
Capture_Ai_V1 Tests
View Details
| Test | Status | Duration |
|---|---|---|
| Endpoint And Method.Targets V1 Endpoint | ✅ | 2843ms |
| Endpoint And Method.Does Not Use Legacy Endpoints | ✅ | 268ms |
| Endpoint And Method.Capture Does Not Reroute Ai Named Events | ✅ | 266ms |
| Required Headers.Has Authorization Bearer Header | ✅ | 2638ms |
| Required Headers.Has Content Type Json | ✅ | 236ms |
| Required Headers.Has Posthog Sdk Info Format | ✅ | 2758ms |
| Required Headers.Has Posthog Attempt Header | ✅ | 2768ms |
| Required Headers.Has Posthog Request Id | ✅ | 2801ms |
| Required Headers.Has Posthog Request Timestamp | ✅ | 2727ms |
| Required Headers.Has User Agent | ✅ | 2748ms |
| Body Format.Body Has Created At And Batch | ✅ | 2833ms |
| Body Format.No Api Key In Body | ✅ | 2745ms |
| Body Format.No Sent At In Body | ✅ | 2879ms |
| Event Format.Event Has Required Root Fields | ✅ | 422ms |
| Event Format.Event Uuid Is Valid | ✅ | 2863ms |
| Event Format.Event Timestamp Is Rfc3339 | ✅ | 2665ms |
| Event Format.Non Utc Event Timestamp Is Converted To Utc | ✅ | 2859ms |
| Event Format.Distinct Id Is String | ✅ | 2878ms |
| Event Format.Distinct Id At Root Not Properties | ✅ | 2850ms |
| Event Format.Custom Properties Preserved | ✅ | 2864ms |
| Event Format.Set Properties Preserved | ✅ | 2781ms |
| Event Format.Set Once Properties Preserved | ✅ | 2815ms |
| Event Format.Groups Properties Preserved | ✅ | 337ms |
| Event Format.Sdk Generates Uuid If Not Provided | ✅ | 2830ms |
| Event Format.Capture Ai Keeps Supplied Uuid | ❌ | 162ms |
| Event Format.Event Has Required Root Fields Batch | ❌ | 493ms |
| Event Format.Event Uuid Is Valid Batch | ✅ | 2814ms |
| Event Format.Event Timestamp Is Rfc3339 Batch | ✅ | 2904ms |
| Event Format.Distinct Id Is String Batch | ✅ | 2890ms |
| Event Format.Distinct Id At Root Not Properties Batch | ✅ | 2891ms |
| Event Format.Custom Properties Preserved Batch | ✅ | 2782ms |
| Event Format.Set Properties Preserved Batch | ✅ | 2920ms |
| Event Format.Set Once Properties Preserved Batch | ✅ | 2980ms |
| Event Format.Groups Properties Preserved Batch | ✅ | 2941ms |
| Event Format.Sdk Generates Uuid If Not Provided Batch | ✅ | 2926ms |
| Batch Behavior.Multiple Events In Single Batch | ✅ | 2822ms |
| Batch Behavior.Batch Envelope Smoke | ✅ | 2938ms |
| Batch Behavior.Flush At Triggers Batch | ✅ | 1241ms |
| Batch Behavior.Created At Reflects Batch Creation Time | ✅ | 2835ms |
| Deduplication.Generates Unique Uuids | ✅ | 3027ms |
| Deduplication.Different Events Same Content Different Uuids | ✅ | 2905ms |
| Deduplication.Preserves Uuid On Retry | ✅ | 9294ms |
| Deduplication.Preserves Timestamp On Retry | ✅ | 9105ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ✅ | 7897ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 3299ms |
| Header Behavior On Retry.Attempt Header Starts At One | ✅ | 3025ms |
| Header Behavior On Retry.Attempt Header Increments On Retry | ✅ | 17104ms |
| Header Behavior On Retry.Request Id Preserved On Retry | ✅ | 9317ms |
| Header Behavior On Retry.Different Requests Have Different Request Ids | ✅ | 7653ms |
| Header Behavior On Retry.Request Timestamp Changes On Retry | ✅ | 9342ms |
| Response Format Validation.Success Response Has Uuid Keyed Results | ✅ | 2826ms |
| Response Format Validation.Success Response Has Ok For Each Event | ✅ | 2838ms |
| Response Format Validation.Success No Retry After When All Ok | ✅ | 2802ms |
| Response Format Validation.Success Retry After Present When Retry Events | ✅ | 3156ms |
| Response Format Validation.Success No Retry After When Drop Only | ✅ | 2842ms |
| Response Format Validation.Response Echoes Request Id | ✅ | 440ms |
| Retry Behavior.Retries On 408 | ✅ | 5479ms |
| Retry Behavior.Retries On 500 | ✅ | 9336ms |
| Retry Behavior.Retries On 503 | ✅ | 11319ms |
| Retry Behavior.Retries On 504 | ✅ | 9217ms |
| Retry Behavior.Retryable Errors Have Retry After | ✅ | 2452ms |
| Retry Behavior.Respects Retry After On Retryable Error | ✅ | 10930ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 4869ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 4893ms |
| Retry Behavior.Does Not Retry On 402 | ✅ | 4812ms |
| Retry Behavior.Does Not Retry On 413 | ✅ | 4868ms |
| Retry Behavior.Does Not Retry On 415 | ✅ | 4767ms |
| Retry Behavior.Non Retryable Errors Have No Retry After | ✅ | 4903ms |
| Retry Behavior.Implements Backoff | ✅ | 21776ms |
| Retry Behavior.Max Retries Respected | ✅ | 15491ms |
| Partial Batch Handling.Handles 200 Full Success | ✅ | 2429ms |
| Partial Batch Handling.Handles 200 With All Ok | ✅ | 5935ms |
| Partial Batch Handling.Does Not Retry Dropped Events | ✅ | 5894ms |
| Partial Batch Handling.Does Not Retry Limited Events | ✅ | 5881ms |
| Partial Batch Handling.Prunes Ok Events On Partial Retry | ✅ | 7869ms |
| Partial Batch Handling.Prunes Dropped Events On Partial Retry | ✅ | 7857ms |
| Partial Batch Handling.Retries Only Retry Events From Partial | ✅ | 7956ms |
| Partial Batch Handling.Partial Retry Preserves Uuids | ✅ | 7929ms |
| Partial Batch Handling.Partial Retry Attempt Header Increments | ✅ | 7799ms |
| Partial Batch Handling.Partial Retry Request Id Preserved | ✅ | 7949ms |
| Partial Batch Handling.Respects Retry After On Partial | ✅ | 7925ms |
| Partial Batch Handling.Unknown Result Treated As Terminal | ✅ | 5989ms |
| Partial Batch Handling.Mixed Ok Drop Limited No Retry | ✅ | 6069ms |
| Compression.Sends Gzip Content Encoding | ✅ | 2856ms |
| Compression.No Content Encoding When Disabled | ✅ | 2874ms |
| Compression.Compressed Body Is Decompressible | ✅ | 323ms |
| Error Handling.Does Not Retry On Unknown 4Xx | ✅ | 4822ms |
| Event Options.Cookieless Mode Override | ✅ | 452ms |
| Event Options.Disable Skew Correction Override | ✅ | 2748ms |
| Event Options.Process Person Profile Override | ✅ | 2927ms |
| Event Options.Product Tour Id Override | ✅ | 561ms |
| Event Options.Unset Options Omitted | ✅ | 479ms |
| Event Options.Options Override In Batch | ✅ | 2954ms |
| Event Options.Unknown Option Passes Through | ✅ | 2881ms |
| Event Options.Option Value Is Not Converted | ✅ | 2892ms |
| Event Options.Lenient Bool Option Values Are Not Converted | ✅ | 2875ms |
| Event Options.Option Wins Over Legacy Property | ✅ | 2729ms |
| Event Options.Legacy Property Fills Unset Option | ✅ | 2685ms |
| Event Options.Null Option Falls Back To Legacy Property | ✅ | 325ms |
| Geoip And Historical Migration.Geoip Disable Injected Into Properties | ✅ | 2841ms |
| Geoip And Historical Migration.Historical Migration Absent By Default | ✅ | 2692ms |
Failures
event_format.capture_ai_keeps_supplied_uuid
Expected last action result '0198c0de-0000-7000-8000-000000000abc', got '01a17eba-a893-7ba8-a0b7-176bf2cb2b12'
event_format.event_has_required_root_fields_batch
Expected 1 requests, got 2
Feature_Flags Tests
✅ 17/17 tests passed
View Details
| Test | Status | Duration |
|---|---|---|
| Request Payload.Request With Person Properties Device Id | ✅ | 2775ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 2735ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 2783ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 2789ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 2910ms |
| Request Payload.Groups Round Trip | ✅ | 2846ms |
| Request Payload.Groups Default To Empty Object | ✅ | 2921ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 2882ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ✅ | 2786ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 2743ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 81ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 488ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 5401ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ✅ | 2882ms |
| Retry Behavior.Retries Flags On 502 | ✅ | 2937ms |
| Retry Behavior.Retries Flags On 504 | ✅ | 2988ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ✅ | 2805ms |
b7e06b5 to
f445734
Compare
|
This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, post a comment or remove the |
0d35bfb to
57c45fb
Compare
57c45fb to
67a45c9
Compare
67a45c9 to
4f56f37
Compare
4f56f37 to
6f1c163
Compare
| **Breaking:** send events to capture V1 (`/i/v1/analytics/events`) with the project token in an `Authorization: Bearer` header. | ||
|
|
||
| - If you use a reverse proxy, forward `/i/v1/analytics/events`. A 404 falls back to `/batch` until the app restarts; other errors such as 403 or 405 drop the events. | ||
| - If you use a reverse proxy or self-host PostHog, make sure `/i/v1/analytics/events` is served: a 404 or other non-retriable response drops the events. |
There was a problem hiding this comment.
fwiw, (nit; paranoid take) i think we could be more resilient than this. a routing misconfiguration would mean certain data loss. considering the route is not configurable and we expect it to exist, it seems reasonable to take a position that a 404 would be retriable (or at least, shouldn't discard the event data) in that it should never happen, and if it did, is likely going to be rectified quickly.
i'm not sure there's many situations where i'd consider outright dropping data from the client (aside from a full event buffer), and perhaps this is something we should think about
There was a problem hiding this comment.
hm I see what you mean. It looks like all the sdks drop this on 404: python, go and node on capture v1, and android/RN/iOS on /batch, replay and logs today. I was removing it in this PR to make it easier to review instead of all in 1. Ultimately we would want it to use capture v1 and not /batch here, but I agree it's worth rethinking, especially for mobile. It might be a bigger change that affects more than capture v1 adn the fallback probably isn’t /batch but some sort of retry.
There was a problem hiding this comment.
I'd lean against retrying 404s here: 3.x didn't retry them on /batch, the other v1 SDKs treat 404 as final, and the draft public docs for this release list only 408, 5xx and network errors as retried. If I'm missing context or you feel strongly we need it, let me know and I'm happy to update the decision (will need to update v1 SDKs and release docs/specs for parity)
There was a problem hiding this comment.
discussed offline, we're pivoting on this and adding 404 and 429 to retry allowlist for all v1 SDKs ✅ thanks again!
There was a problem hiding this comment.
Covered by #979: capture v1 and the AI endpoint now retry 404 and 429.
6f1c163 to
9f5f51c
Compare
9f5f51c to
f11308f
Compare
|
|
||
| let path = strippingAPIHostPathPrefix(from: url.path, apiHostPath: apiHost.path) | ||
| let ignoredPaths = [snapshotEndpoint, "/batch", "/e/", "/i/"] | ||
| let ignoredPaths = [snapshotEndpoint, "/e/", "/i/"] |
There was a problem hiding this comment.
Could we keep /batch in the replay network ignore list? iOS no longer sends there, but React Native apps record replay through posthog-ios while their JS SDK still posts to /batch/, so once the RN replay plugin moves to posthog-ios 4.x, those requests would start showing up in recordings.
There was a problem hiding this comment.
ooh good catch!
| **Breaking:** send events to capture V1 (`/i/v1/analytics/events`) with the project token in an `Authorization: Bearer` header. | ||
|
|
||
| - If you use a reverse proxy, forward `/i/v1/analytics/events`. A 404 falls back to `/batch` until the app restarts; other errors such as 403 or 405 drop the events. | ||
| - If you use a reverse proxy or self-host PostHog, make sure `/i/v1/analytics/events` is served: a 404 or other non-retriable response drops the events. |
There was a problem hiding this comment.
This PR removes the /batch fallback, but the 4.0 migration guide still says a 404 falls back to /batch (endpoints table, 'Hosts without capture v1', the options section, and the last retry bullet). When this restacks on #938, can the guide say a 404 drops the events, like the changeset does?
There was a problem hiding this comment.
Done in a7797fc: the guide no longer mentions the /batch fallback and says a 404 drops the events, like the changeset.
2330981 to
7397e38
Compare
17b4d3f to
a7797fc
Compare
a7797fc to
80b63fe
Compare
26d55cb to
2392cbd
Compare
50c3a23 to
41cdd36
Compare
41cdd36 to
53dc865
Compare
53dc865 to
90318f4
Compare
Analytics events now only go to /i/v1/analytics/events. A 404 is terminal like any other non-retriable status, matching posthog-python, posthog-go and posthog-rs, instead of resending the batch to /batch for the session. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The SDK no longer sends to /batch, so replay doesn't need to filter it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A 404 from capture v1 now drops the events, as the changeset says. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
React Native apps record replay through posthog-ios while their JS SDK still posts to /batch, so those requests would show up in recordings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
39f4d4e to
65b2cc3
Compare
| ### Hosts without capture v1 | ||
|
|
||
| If you use a reverse proxy, forward `/i/v1/analytics/events` before you upgrade. | ||
| If you use a reverse proxy or self-host PostHog, make sure `/i/v1/analytics/events` is served before you upgrade. |
There was a problem hiding this comment.
Could this line also cover the rest of what a reverse proxy needs for capture v1: forward /i/v1/ai/events too, pass Authorization and every PostHog-* header through unchanged (PostHog answers 401 or 400 without them), and accept request bodies up to 20 MB (nginx and ingress-nginx default to 1 MB)? The server SDK guides use this checklist: https://github.com/PostHog/posthog-python/blob/235047e220c48e1a69ab7354564ceefe035c4b34/docs/migration-7.x-to-8.0.md#L44-L50
There was a problem hiding this comment.
Added in 3479164: both endpoints, the header list and the 20 MB body limit. On a 413 the guide says what iOS does: it splits the batch and drops only an event that is still too large on its own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-remove-batch-merge # Conflicts: # PostHog/PostHogApi.swift
💡 Motivation and Context
Stacked on #939 (
captureAi) and #938. Removes the iOS-only/batchfallback so analytics events only go to capture V1 (/i/v1/analytics/events), matching posthog-python 8.0, posthog-go 2.0 and posthog-rs 1.0. #938 kept the fallback as a removable piece so we can decide separately whether 4.0 keeps it: merge this PR to drop it, or close it to keep it./batch.PostHogApi.batch(events:), the per-session "V1 unavailable" flag, the/batchretry policy for events and the options-to-legacy-properties fold-back./snapshotkeeps its own retry policy, unchanged./i/v1/analytics/events.Trade-off: a self-hosted instance or reverse proxy that doesn't serve the V1 route drops events until it serves that route, with no client-side fallback for apps already installed.
💚 How did you test it?
/batchendpoint-path, gzip and custom-header tests inPostHogApiTestto capture V1.main, includingtest-ios-simulator,test-no-traitsandPublic API snapshot.make lintpasses, andmake testran 1185 tests. The only failures are the 13 known group-containerPostHogStorageTestissues ("Operation not permitted" locally).capture_v198/101 andcapture_ai_v197/101, the same failures as feat!: send events through capture v1 and add captureAi #938 and feat: add captureAi on the capture V1 AI endpoint #939.📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset file (updated.changeset/v4-capture-v1.md)🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Built with Claude Code as a stacked follow-up to #938.
🤖 Generated with Claude Code