En resumen: La Atribución People-Based (PBA) está siendo sustituida por la medición de performance web, la solución mejorada de AppsFlyer para la medición web. Este artículo explica qué cambia, los pasos de la migración y el mapeo completo de campos para tus reportes e integraciones del lado del servidor.
Por qué estamos mejorando tu medición web
La medición web es más importante que nunca. El sitio web es donde muchos de tus usuarios convierten y donde comienza el recorrido hacia tu aplicación móvil. No es solo una landing page; es un funnel de adquisición completo que incluye flujos de cuestionarios, onboarding personalizado, paywalls y tiendas web que suelen atraer a usuarios con mayor intención a un costo de adquisición menor.
AppsFlyer está llevando la medición web al mismo nivel que la medición móvil. La Atribución People-Based (PBA), el producto web heredado, está siendo sustituido por la medición de performance web, desarrollada sobre el motor de atribución principal y el modelo de datos unificado de AppsFlyer. La medición de performance web ofrece todas las funcionalidades actuales de PBA y, además, incorpora:
- Una single source of truth, con la medición de la web y la aplicación móvil en un solo lugar, junto con la agregación de costos, los postbacks de optimización y la optimización de creatividades.
- Mejores decisiones presupuestarias, con una atribución flexible que se adapta a la lógica de tu negocio para que puedas aumentar la inversión en las campañas que realmente funcionan.
- ROAS mejorado, con postbacks de optimización enriquecidos para tus ad networks y una configuración completa del lado del servidor que mide más conversiones, para que las redes puedan optimizar utilizando mejores señales.
- ROI multiplataforma real, mide cada recorrido del usuario en la web, la aplicación y cualquier otra plataforma.
- Reportes sencillos y unificados, un único dashboard y un único conjunto de reportes de datos para todas las plataformas, actualizados cada hora.
Nota
El cambio requiere un esfuerzo mínimo por tu parte. Mantendrás el mismo SDK web, sin necesidad de realizar cambios en el código de tu sitio web.
¡Importante!
Ten en cuenta que habrá algunas diferencias en las cifras. La lógica de atribución de la medición de performance web es más avanzada y flexible, por lo que las cifras no coincidirán exactamente con las de PBA.
Medición de performance web vs PBA
| Capacidad | Descripción | PBA | Medición de performance web |
|---|---|---|---|
| Datos | |||
| Actualización de los datos | Rapidez con la que los datos están disponibles para los reportes | ✗ A diario | ✓ Reportes por hora, con aproximadamente 2 horas de retraso en la actualización de los datos |
| Modelo de datos | Alineación del esquema con los datos de atribución móvil | ✗ Diferente al de dispositivos móviles | ✓ Alineado con los datos móviles, fácil de combinar y analizar |
| Reportes | |||
| Dashboard de actividad | Dashboard basado en la hora del evento | ✓ Compatible | ✓ Compatible |
| Dashboard de cohorte | Analiza el performance por cohorte de adquisición a lo largo del tiempo | ✗ No compatible | ✓ Compatible |
| Raw data de Data Locker | Acceso a raw data de atribución mediante la exportación de Data Locker | ✓ Compatible | ✓ Compatible |
| Granularidad a nivel de anuncio | Desglose de los reportes desde el nivel de campaña hasta el nivel de anuncio | ✗ Solo en el dashboard, no en los raw data | ✓ Granularidad completa de las campañas tanto en el dashboard como en los raw data |
| LTV multiplataforma | Unifica los recorridos de usuarios de la web y los dispositivos móviles en un único LTV | ✗ No compatible | ✓ Compatible |
| Costos y señales | |||
| Costos web | Ingiere y genera reportes sobre la inversión publicitaria de las campañas web | ✗ No compatible | ✓ Compatible |
| Postbacks de optimización | Envía señales de optimización a las ad networks | ✗ No compatible | ✓ Compatible |
| Implementación | |||
| SDK Web (píxel) | SDK del lado del cliente para medir visitas y eventos web | ✓ Compatible | ✓ El mismo SDK, sin necesidad de realizar cambios en el código |
| Compatibilidad con S2S | Medición completa del lado del servidor para visitas y eventos | ✗ Solo eventos | ✓ Eventos y visitas Admite una implementación completa del lado del servidor. |
| Motor de atribución | |||
| Ventanas de atribución | Ventanas de lookback, de atribución, de re-engagement y de inactividad configurables | ✗ Solo ventanas de lookback de clics | ✓ 5 ventanas configurables (control total) |
| Evento de UA personalizado | Define qué evento se considera una adquisición de usuario más allá de la primera visita | ✗ Solo la primera visita | ✓ Cualquier evento personalizado (por ejemplo, registro o compra) |
| UA vs retargeting | Crédito de atribución para nuevas adquisiciones vs re-engagement | ✗ Sin concepto de UA; los eventos se atribuyen al último toque | ✓ Vistas específicas de UA y retargeting con doble atribución |
Pasos de la migración
La siguiente tabla divide la migración en cinco pasos. La creación de una aplicación web es necesaria para todos; el resto de los pasos dependen de las funcionalidades de PBA que utilices actualmente, como la API S2S o los reportes de Data Locker.
| Acción | Relevante para | En qué consiste |
|---|---|---|
| Crear una aplicación web | Todos | Cuando crees la nueva aplicación web, selecciona tu Dev Key web actual en el campo ID del SDK web. De este modo, el código actual de tu sitio web seguirá funcionando tal cual, sin necesidad de realizar cambios. A continuación, configura los ajustes de atribución en la nueva aplicación. |
| Migrar a la nueva API S2S | Usuarios de la API S2S de PBA | Configura la nueva API S2S. Admite tanto visitas como eventos, por lo que puedes realizar una implementación completamente del lado del servidor. Consulta el apéndice sobre la migración de la API S2S que aparece a continuación. |
| Migrar a los nuevos reportes de Data Locker | Usuarios de los reportes de Data Locker de PBA | Habilita el nuevo reporte web en la interfaz de usuario y configura tu BI/ETL para que utilice los datos actualizados. Los nuevos reportes utilizan un único esquema compartido entre todas las plataformas: aplicaciones móviles, sitios web, CTV y PC. Consulta el apéndice sobre el mapeo de campos de raw data que aparece a continuación. |
| Revisar los parámetros de atribución | Recomendado | PBA aplicaba sus propias reglas de atribución de fuente de medios. La medición de performance web utiliza una resolución mejorada de las fuentes de tráfico para ofrecer análisis más precisos. Revisa las diferencias para saber qué valores puedes esperar en tus reportes. Consulta el apéndice de comparación de la resolución de fuentes de tráfico que aparece a continuación. |
| Agrupar aplicaciones en una línea de productos | Opcional | Crea una línea de productos y agrupa la aplicación web con tus aplicaciones móviles para habilitar los reportes de LTV de usuarios multiplataforma (similares a PBA Brand Bundle). |
Nota
Ten en cuenta que habrá algunas diferencias en las cifras. La lógica de atribución de la medición de performance web es más avanzada y flexible, por lo que las cifras no coincidirán exactamente con las de PBA. La lógica de registro de sesiones no cambia; una sesión sigue teniendo una duración de 30 minutos de actividad, el estándar del mercado.
Funcionalidades que dejarán de estar disponibles
| Capacidad | Qué cambia | Detalles |
|---|---|---|
| Ruta de conversión | Ya obsoleta. | — |
| Instalaciones asistidas por la web (atribución a una campaña web que contribuyó a generar posteriormente una instalación móvil) | No hay una vista específica de “instalaciones asistidas por la web”. |
Los recorridos web-to-app se miden con Smart Script y Smart Banner. El reporte multiplataforma proporciona un análisis similar, aunque no idéntico. Al igual que PBA, se basa en CUID:
|
| Recálculo retroactivo | No se realiza ningún recálculo retroactivo más allá del retraso predeterminado de 30 minutos. | La atribución se finaliza tras un retraso de 30 minutos, lo que da tiempo a los usuarios para identificarse dentro de esa ventana. |
| Campos de raw data | Los campos relacionados con dispositivos móviles quedan obsoletos para la web. Se cambia el nombre de algunos campos y se modifican algunos valores. | Consulta el apéndice sobre el mapeo de campos de raw data que aparece a continuación. |
| Eventos S2S recibidos con retraso | Los eventos que llegan más de 30 minutos después de que finalice el día UTC en el que se produjeron se siguen aceptando, pero la hora del evento se sustituye por la hora en la que AppsFlyer los recibió. | Envía los eventos en tiempo real, preferiblemente en los 30 minutos posteriores a que se produzcan, en lugar de agruparlos en una única carga diaria. Una atribución precisa depende de que los eventos se reciban poco después de que se produzcan. Esto alinea el comportamiento de la web con el comportamiento actual de los dispositivos móviles. |
Apéndice: cambios en los reportes de raw data
Mapeo único de todos los campos del reporte de raw data de PBA (visitas y eventos del sitio web) al nuevo reporte de eventos del usuario final. Fuente: Reportes de raw data de PBA.
Alcance: los reportes de visitas al sitio web y eventos del sitio web de PBA.
- Sin cambios, mismo nombre de campo y mismos datos.
- Renombrado, mismos datos, nuevo nombre de columna.
- Redefinido, nombre igual o similar, pero cambian los datos o el formato de los valores (debe revisarse antes de volver a utilizarlo).
- Obsoleto, sin equivalente en el nuevo reporte.
| Nombre del campo | Descripción | Estado | Nuevo campo/nota |
|---|---|---|---|
advertising_id |
ID de publicidad (GAID) | Obsoleto | ID de publicidad del dispositivo móvil, unificado entre plataformas en PBA. Los reportes de LTV multiplataforma y recorrido de usuarios se basan en CUID y no utilizan este campo. |
af_web_id |
ID de cookie enviado desde el SDK web | Renombrado |
appsflyer_id_value, misma cookie web. |
amazon_aid |
ID de publicidad de Amazon Fire TV | Obsoleto | ID de dispositivo móvil, no relevante para la web. |
android_id |
ID de dispositivo de Android | Obsoleto | ID de dispositivo móvil, no relevante para la web. |
app_id |
ID de la aplicación instalada más recientemente | Obsoleto | Campo multiplataforma para dispositivos móviles. El identificador de la aplicación web en el nuevo reporte es unified_app_id ("website-{domain}"), un concepto diferente. |
app_name |
Nombre de la aplicación más reciente | Sin cambios |
app_name. |
app_version |
Versión más reciente de la aplicación | Obsoleto | Campo multiplataforma para dispositivos móviles, no relevante para la web. |
appsflyer_id |
ID de AppsFlyer (instalación) | Obsoleto | ID de instalación móvil. El nuevo appsflyer_id_value es la cookie web (af_web_id), un identificador diferente. |
attributed_touch_time |
Marca de tiempo de la visita web (atribuida) | Renombrado |
event_time__attribution, la hora del toque atribuido (engagement). |
attributed_touch_type |
Tipo de toque, siempre "web visit" | Obsoleto | Valor constante en PBA. La distinción entre visita y evento ahora se encuentra en end_user_event_type (SESSION / IN_APP). |
bundle_id |
ID de paquete de PBA | Obsoleto | Sustituido por la agrupación Product Line (web + aplicaciones móviles) en el reporte multiplataforma. |
campaign |
Atribuido a la visita al sitio web | Renombrado |
campaign_name. |
campaign_id |
Atribuido a la visita al sitio web | Sin cambios |
campaign_id. |
city |
Resuelto utilizando la dirección IP | Sin cambios |
city. |
country_code |
Resuelto utilizando la dirección IP | Sin cambios |
country_code. |
customer_user_id |
Identificador de usuario del cliente (CUID) | Sin cambios |
customer_user_id. |
device_type |
El tipo de dispositivo | Renombrado |
device_category, los valores son diferentes ("Desktop" frente a "MOBILE_PHONE" / "TV"). |
dma |
Resuelto utilizando la dirección IP | Sin cambios |
dma. |
event_name |
Visitas: siempre "website visit". Eventos: nombre del evento enviado | Redefinido | Vacío en las visitas (PBA mostraba "website visit"). Sin cambios para los eventos. |
event_revenue |
Importe de ingresos en la divisa del evento | Renombrado |
revenue_value_original. |
event_revenue_currency |
Código de moneda de 3 dígitos de event_revenue
|
Renombrado |
revenue_currency_original. |
event_revenue_usd |
event_revenue convertido a USD |
Renombrado |
revenue_usd. |
event_source |
El SDK web o Server-to-server | Sin cambios |
event_source. |
event_time |
Visitas: hora de la visita. Eventos: hora del evento | Sin cambios |
event_time. |
event_type |
Evento estándar/evento de conversión/visita al sitio web | Redefinido | La identificación de eventos de conversión deja de existir. La distinción entre visita y evento se encuentra en end_user_event_type (SESSION / IN_APP). |
event_url |
URL de la página web donde se produjo el evento (equivale a Original URL en las visitas) | Sin cambios |
event_url, ahora también es el lugar principal donde consultar los parámetros de consulta de la URL (UTM, etc.). |
event_value |
Eventos: detalles del evento en formato JSON. Visitas: null | Sin cambios |
event_value. |
idfa |
Identificador de publicidad | Obsoleto | ID de dispositivo móvil, no relevante para la web. |
idfv |
Identificador de publicidad | Obsoleto | ID de dispositivo móvil, no relevante para la web. |
imei |
Identificador de dispositivo | Obsoleto | ID de dispositivo móvil, no relevante para la web. |
install_time |
Hora de la instalación más reciente de la aplicación | Obsoleto | Campo multiplataforma para dispositivos móviles. La hora de adquisición de usuarios (conversión) web es event_time__conversion, un concepto diferente. |
ip |
Dirección IP del visitante | Renombrado |
ip_address_value, mismo valor, además de ip_address_type para el método de hashing. |
language |
Indicado por el agente de usuario (por ejemplo, "English") | Redefinido |
language, el formato del valor cambia a ISO 639-1 y al código de país. |
media_channel |
Atribuido a la visita al sitio web ("Ad") | Obsoleto | Se puede obtener mediante sub_param_1-5 si es necesario. |
media_source |
Atribuido a la visita al sitio web | Sin cambios |
media_source. |
media_type |
Atribuido a la visita al sitio web | Obsoleto | Vacío para la web. La distinción entre orgánico y de pago ahora viene determinada por el valor booleano is_organic. |
oaid |
Identificador de publicidad | Obsoleto | ID de dispositivo móvil, no relevante para la web. |
original_url |
URL que redirigió al usuario en la visita atribuida | Renombrado | Consolidado en event_url (en las visitas, event_url equivale a la URL original). La columna independiente deja de existir. |
platform |
La plataforma ("macOS", "Windows") | Redefinido | La plataforma siempre es "WEBSITE". El sistema operativo se ha trasladado a os_version / user_agent. |
postal_code |
Resuelto utilizando la dirección IP | Sin cambios |
postal_code. |
query_params |
Parámetros de consulta de la URL de redirección, en formato JSON | Obsoleto | La cadena de raw query se encuentra en event_url; la columna de JSON procesado deja de existir. |
referrer |
HTTP referrer de la visita atribuida al sitio web | Renombrado |
http_referrer. |
region |
Determinado mediante la dirección IP ("NA") | Renombrado |
continent, código de continente, por ejemplo, "NA". |
state |
Resuelto utilizando la dirección IP | Sin cambios |
state. |
Prompt listo para usar para un agente de programación para la migración de ETL de Data Locker
Para facilitar esta transición, hemos preparado un prompt listo para usar para tu agente de programación con IA (Claude Code, Cursor o similar). Da al agente acceso a tu código ETL actual y pega el siguiente prompt; contiene el mapeo completo de campos y todas las diferencias de comportamiento. El prompt guiará al agente para que comprenda tu pipeline actual y lo vuelva a crear para el nuevo reporte.
You are migrating an ETL pipeline from AppsFlyer's legacy PBA Data Locker raw-data reports (Website visits + Website events) to AppsFlyer's Web Performance Measurement Data Locker report (End User Events). Everything you need is in this prompt: the structural changes, the complete field-by-field mapping, and the validation steps. Do not guess anything beyond what is written here; if something is ambiguous, ask me.
## Step 1: Learn the current pipeline
Before writing any code, explore the existing codebase and produce an inventory:
1. Which PBA reports we consume (Website visits, Website events, or both) and where they are ingested.
2. Every PBA field we read, and where each is used downstream (transforms, joins, dashboards, alerts, exports).
3. The load cadence and scheduling assumptions (PBA delivered daily).
4. Any logic that separates or joins visit rows and event rows.
5. Any filters, groupings, or hardcoded values keyed on PBA field values (e.g. media_source names, channel labels, event_type, platform values).
Present this inventory to me and wait for my confirmation before proceeding.
## Step 2: Ask me these questions
1. Is the new End User Events report already enabled in Data Locker (enabled from the AppsFlyer UI)? If not, I need to enable it first.
2. What is our new web app's Unified App ID? Format: "website-{domain}" (e.g. website-www.example.com). If I don't know it, I'll get it from the AppsFlyer dashboard before we continue.
3. Do we want a parallel-run period (old and new pipelines side by side, comparing outputs) or a direct cutover? Recommend parallel-run.
4. Should the new pipeline also consume the Conversions report (unique attribution instances, no duplicate rows) or the cross-platform End User Events report (CUID-deduplicated, web+mobile user-level)? Default scope is the platform-level End User Events report, the direct successor of the PBA reports.
## Structural changes to design around
1. **One report instead of two.** PBA split visits and events into two reports. The new End User Events report holds both: visits are rows with end_user_event_type = 'SESSION', events are rows with end_user_event_type = 'IN_APP'. Only IN_APP rows carry a valid event_name; on SESSION rows event_name is empty (PBA wrote "website visit" there).
2. **One schema across platforms.** The report is shared by website, mobile, CTV, and PC. Always filter platform = 'WEBSITE' to isolate web data.
3. **Dual attribution credit, deduplicate.** The same action can appear twice: a primary-credit row and a secondary-credit row (original UA source, for UA-view LTV). Filter is_primary_attribution = true by default to avoid double-counting. Drop the filter only for dedicated UA-view vs retargeting-view analysis using conversion_type.
4. **Hourly instead of daily.** The new report delivers hourly with approximately 2 hours of data freshness. Redesign incremental loads around hourly batches instead of a daily drop.
5. **Organic vs paid.** PBA's media_type ("Paid") is gone. Use the is_organic boolean; never infer organic/paid from media_source.
6. **User counting.** Count and join users with COALESCE(customer_user_id, appsflyer_id_value), the stable customer user ID first, the cookie-based ID as fallback.
7. **Empty values.** STRING fields are '', NUMERIC fields are NULL.
## Field-by-field mapping (PBA → End User Events)
Status legend: Unchanged = same name and data. Renamed = same data, new column. Redefined = data or value format changes (handle with care). Deprecated = no equivalent.
| PBA field | Status | New field / handling |
|---|---|---|
| advertising_id | Deprecated | Mobile/device ID. Cross-platform reports are CUID-based; drop it. |
| af_web_id | Renamed | appsflyer_id_value, same web cookie. |
| amazon_aid | Deprecated | Mobile/device ID, not relevant for web. |
| android_id | Deprecated | Mobile/device ID, not relevant for web. |
| app_id | Deprecated | Mobile cross-platform field. The new web app identifier is unified_app_id ("website-{domain}"), a different concept, not a rename. |
| app_name | Unchanged | app_name. |
| app_version | Deprecated | Mobile cross-platform field. |
| appsflyer_id | Deprecated | Mobile install ID. Note: the new appsflyer_id_value is the web cookie (PBA's af_web_id), NOT this field. |
| attributed_touch_time | Renamed | event_time__attribution. |
| attributed_touch_type | Deprecated | Was a constant. Visit-vs-event now lives in end_user_event_type. |
| bundle_id | Deprecated | Replaced by the Product Line grouping in the cross-platform report. |
| campaign | Renamed | campaign_name. |
| campaign_id | Unchanged | campaign_id. |
| city | Unchanged | city. |
| country_code | Unchanged | country_code. |
| customer_user_id | Unchanged | customer_user_id. |
| device_type | Renamed + values change | device_category, values differ (e.g. "Desktop" → "MOBILE_PHONE" / "TV" style values). Update any value-keyed logic. |
| dma | Unchanged | dma. |
| event_name | Redefined | Events: unchanged. Visits: now empty (PBA wrote "website visit"). Use end_user_event_type = 'SESSION' to identify visits. |
| event_revenue | Renamed | revenue_value_original. |
| event_revenue_currency | Renamed | revenue_currency_original. |
| event_revenue_usd | Renamed | revenue_usd. |
| event_source | Unchanged | event_source. |
| event_time | Unchanged | event_time. |
| event_type | Redefined | "Conversion event" marking no longer exists. Visit-vs-event lives in end_user_event_type (SESSION / IN_APP). |
| event_url | Unchanged | event_url, now also the primary place URL query params (UTMs, etc.) are read from. |
| event_value | Unchanged | event_value. |
| idfa / idfv / imei / oaid | Deprecated | Mobile/device IDs, not relevant for web. |
| install_time | Deprecated | Mobile field. The web user-acquisition time is event_time__conversion, a separate concept. |
| ip | Renamed | ip_address_value (plus ip_address_type for the hashing method). |
| language | Redefined | language, format changes to ISO 639-1 + country code (was e.g. "English"). |
| media_channel | Deprecated | Can be covered by sub_param_1-5 if needed. |
| media_source | Unchanged | media_source (but see value renames below). |
| media_type | Deprecated | Use the is_organic boolean instead. |
| original_url | Renamed | Consolidated into event_url (on visits, event_url equals the original URL). Standalone column gone. |
| platform | Redefined | platform is always "WEBSITE". The OS moved to os_version / user_agent. |
| postal_code | Unchanged | postal_code. |
| query_params | Deprecated | The raw query string lives in event_url; the parsed-JSON column is gone. Re-implement parsing from event_url if needed. |
| referrer | Renamed | http_referrer. |
| region | Renamed | continent, continent code (e.g. "NA"). |
| state | Unchanged | state. |
## Attributed-value changes (update filters and groupings)
The attribution engine resolves traffic sources differently, so some VALUES change even where field names don't:
- media_source renames: doubleclick_int → dv360_int (Google display/video via UTM); "X Ads" → "Twitter" (Twitter via UTM). More PID values now remap to display names (e.g. iossearchads_int → Apple Search Ads, metweb_int → Facebook Ads, tiktokweb_int → tiktokglobal_int, snapweb_int → snapchat_int).
- Channel labels change format: Direct / Organic search / Social media / Email / Ad / Referral / Other become DIRECT / ORGANIC_SEARCH / SOCIAL_MEDIA / EMAIL / AD / REFERRAL / OTHER.
- Click-ID coverage expanded (more networks resolve from click IDs); dclid alone no longer resolves; fbclid is not used.
Scan the codebase for any filter, CASE, join key, or dashboard grouping keyed on these old values and update them.
## Step 3: Build
1. Propose the new ETL design (ingestion, schema, incremental hourly logic, the mandatory filters from "Structural changes").
2. After my approval, implement it, reusing our existing conventions and infrastructure.
3. For every Deprecated field the inventory found in downstream use, list the consumer and propose a resolution (drop, replace with the suggested alternative, or flag to the business owner).
## Step 4: Validate
1. Run both pipelines on the same day range and compare: visits (SESSION rows) vs PBA website visits, events (IN_APP rows) vs PBA website events, and revenue totals.
2. Expect differences, not equality: the new attribution logic is more advanced, so attributed dimensions (media_source, campaign) will not match PBA exactly. Session counting logic is unchanged (30 minutes of activity), so visit volumes should be in the same ballpark.
3. Verify the is_primary_attribution filter is applied everywhere; its absence shows up as inflated event counts.
4. Produce a short migration report: what was mapped, what was dropped, what changed in values, and any open items for the business owner.
Apéndice: Migración de PBA Web-S2S a la nueva API S2S
Si envías eventos a PBA mediante la API de eventos web Server-to-server (Web-S2S), migra a la nueva API S2S. La nueva API admite tanto visitas como eventos, por lo que tu sitio web puede funcionar completamente del lado del servidor; la API S2S de PBA solo aceptaba eventos.
Endpoints y autenticación
| PBA Web-S2S | Nueva API S2S | |
|---|---|---|
| URL base | https://webs2s.appsflyer.com |
https://events.appsflyer.com |
| Llamada de evento | POST /v1/{bundleId}/event |
POST /v2.0/s2s/inapps/app/web/{appId} |
| Llamada de visita | No disponible (las visitas procedían únicamente del SDK web) | POST /v2.0/s2s/visits/app/web/{appId} |
| Llamada de identidad |
POST /v1/{bundleId}/setcuid (llamada independiente para asociar un CUID con un usuario web) |
Ninguna; la identidad se envía directamente en el objeto user_id con cada evento/visita |
| Identificador de la aplicación |
bundleId (ID del brand bundle) en la ruta |
appId = el unified_app_id web ("website-{domain}") en la ruta |
| Autenticación |
webDevKey dentro del cuerpo JSON en cada llamada |
Encabezado de autorización que contiene la API key de S2S |
| Tipo de contenido | application/json |
application/json |
| Respuesta correcta | 200 OK | 202 Aceptado |
Mapeo de campos del payload
| Campo de PBA Web-S2S | Nuevo campo S2S | Nota |
|---|---|---|
customerUserId |
user_id.customer_user_id |
Ahora está anidado en el objeto user_id. |
afUserId |
user_id.appsflyer_id |
Ahora está anidado en el objeto user_id. Envía al menos uno de los dos, customer_user_id o appsflyer_id; envía ambos siempre que el usuario esté identificado. |
webDevKey |
— | Eliminado del cuerpo. La autenticación se ha trasladado al encabezado de autorización; la aplicación se identifica mediante appId en la ruta. |
eventType (siempre EVENT) |
— | Eliminado. El endpoint (/inapps frente a /visits) determina el tipo. |
eventName |
event_name |
Entre 1 y 64 caracteres; no puede contener @ = + -. |
timestamp (Unix ms, 13 dígitos) |
timestamp (Unix ms) |
Mismo formato. Se recomienda incluirlo en cada llamada; si se omite, AppsFlyer utiliza la hora de recepción. |
eventValue |
event_value |
Formato libre; admite un subobjeto custom_parameters. |
eventRevenue |
event_revenue |
Ahora es opcional (PBA lo requería para los dashboards). |
eventRevenueCurrency |
event_revenue_currency |
Ahora es opcional (PBA lo requería para los dashboards). |
referrer |
http_referrer |
Renombrado. |
userAgent |
user_agent |
Renombrado. |
ip |
ip |
Sin cambios. |
| — | event_url |
Nuevo. Obligatorio en las visitas; opcional en los eventos. |
| — | customer_dedup_id |
Nuevo. Elimina los duplicados del mismo evento que llegue desde otra fuente (por ejemplo, el SDK web). |
| — |
email_hashed, phone_number_hashed, phone_number_e164_hashed, first_name_hashed, last_name_hashed
|
Nuevo. SHA256 (hexadecimal en minúsculas de 64 caracteres) de los valores normalizados, para el enriquecimiento de la identidad. |
Notas sobre la API S2S
- Ahora las visitas se procesan del lado del servidor. La API S2S de PBA solo aceptaba eventos; las visitas tenían que proceder del SDK web. El nuevo endpoint /visits permite que el sitio web funcione completamente del lado del servidor.
- Ya no se necesita la llamada setcuid. PBA requería el SDK web, por lo que se necesitaba una llamada independiente para asociar un CUID a un usuario web. La nueva API incluye la identidad directamente en cada solicitud, por lo que este paso deja de ser necesario.
- Ventana de datos recibidos con retraso. Envía los eventos y las visitas en tiempo real, preferiblemente en los 30 minutos posteriores a que se produzca el evento, en lugar de agruparlos en una única carga diaria. Los datos que llegan más de 30 minutos después de que finalice el día UTC en el que se produjo el evento se siguen aceptando, pero la hora del evento se sustituye por la hora en la que AppsFlyer los recibió.
Migración del servicio S2S: prompt listo para usar para un agente de programación
Si envías eventos mediante la API Server-to-server de PBA, hemos preparado un prompt listo para usar para tu agente de programación con IA (Claude Code, Cursor o similar). Da al agente acceso al servicio que envía eventos a AppsFlyer y pega el siguiente prompt; contiene el mapeo completo de endpoints y payloads. El prompt guiará al agente para que comprenda tu implementación actual y cree la versión actualizada.
You are migrating a server-side integration from AppsFlyer's legacy PBA Web S2S events API (webs2s.appsflyer.com) to AppsFlyer's new S2S API for Web Performance Measurement (events.appsflyer.com). Everything you need is in this prompt: endpoints, authentication, the complete payload mapping, and the behavior changes. Do not guess anything beyond what is written here; if something is ambiguous, ask me.
## Step 0: Ask me these questions before touching code
1. Should we modify the existing service in place, or create a new service/module alongside it (allowing a parallel-run and clean cutover)? Recommend a new module alongside.
2. Do I know our new web app's Unified App ID? Format: "website-{domain}" (e.g. website-www.example.com). It replaces PBA's bundle ID in the URL path. If I don't know it, I'll get it from the AppsFlyer dashboard before we continue.
3. Do I have the new S2S API key? Authentication moved from the webDevKey in the request body to an Authorization header carrying this key. If I don't have it, I'll retrieve it from the AppsFlyer dashboard.
4. Do we want to send events only (like PBA), or adopt the new visits endpoint too? The new API supports server-side visits, so the website can run fully server-side; PBA accepted events only.
5. Is the AppsFlyer Web SDK still running on our site? (Determines whether visits come from the SDK and whether we need event deduplication between SDK and S2S.)
## Step 1: Learn the current service
Explore the codebase and produce an inventory:
1. Every call site to webs2s.appsflyer.com, the /event calls and any /setcuid calls.
2. The fields populated on each call (customerUserId, afUserId, eventName, eventValue, eventRevenue, timestamp, referrer, userAgent, ip, etc.) and where their values come from.
3. Error handling and monitoring keyed on the 200 OK response.
4. Retry, batching, and queueing behavior.
Present this inventory to me and wait for my confirmation before proceeding.
## What changed: endpoints and authentication
| | PBA Web-S2S (old) | New S2S API |
|---|---|---|
| Base URL | https://webs2s.appsflyer.com | https://events.appsflyer.com |
| Event call | POST /v1/{bundleId}/event | POST /v2.0/s2s/inapps/app/web/{appId} |
| Visit call | Not available | POST /v2.0/s2s/visits/app/web/{appId} |
| Identity call | POST /v1/{bundleId}/setcuid | None, identity is inline in the user_id object on every call |
| App identifier in path | bundleId (brand bundle ID) | appId = the web Unified App ID ("website-{domain}") |
| Authentication | webDevKey in the JSON body | Authorization header with the S2S API key |
| Content type | application/json | application/json (415 if missing) |
| Success response | 200 OK | 202 Accepted |
## Payload field mapping
| PBA field | New field | Note |
|---|---|---|
| customerUserId | user_id.customer_user_id | Nested in the user_id object. |
| afUserId | user_id.appsflyer_id | Nested in the user_id object. Send at least one of customer_user_id or appsflyer_id; send both whenever the user is identified. |
| webDevKey | (removed) | Auth moved to the Authorization header; the app is identified by appId in the path. |
| eventType (always "EVENT") | (removed) | The endpoint (/inapps vs /visits) determines the type. |
| eventName | event_name | 1-64 chars; cannot contain @ = + - characters. |
| timestamp (Unix ms) | timestamp (Unix ms) | Same format. Recommended on every call; if omitted, AppsFlyer uses receive time. |
| eventValue | event_value | Free-form; supports a custom_parameters sub-object. |
| eventRevenue | event_revenue | Now optional (PBA required it for dashboards). |
| eventRevenueCurrency | event_revenue_currency | Now optional (PBA required it for dashboards). |
| referrer | http_referrer | Renamed. |
| userAgent | user_agent | Renamed. |
| ip | ip | Unchanged. |
| (new) | event_url | Required on visits; optional on events. |
| (new) | customer_dedup_id | Deduplicates against the same event arriving from another source (e.g. the Web SDK). |
| (new) | email_hashed, phone_number_hashed, phone_number_e164_hashed, first_name_hashed, last_name_hashed | SHA256 (64-char lowercase hex) of normalized values, for identity enrichment. |
## Behavior changes and gotchas
1. **appId is the Unified App ID, not the "Web SDK ID".** The AppsFlyer app settings page shows a "Web SDK ID" UUID (the former Web Dev Key, kept for SDK continuity). The S2S path must carry the Unified App ID ("website-{domain}"), never that UUID. A 401 "app not found" usually means a wrong appId in the path or a missing/invalid Authorization header.
2. **Success is 202, not 200.** Update health checks, retries, and alerting accordingly.
3. **Don't validate against the old endpoint.** The legacy endpoint may still return 200, but that response is not proof that data reached Web Performance Measurement. Always verify events actually appear in the new web app's data.
4. **Drop the setcuid flow entirely.** Identity travels inline in the user_id object on every event and visit.
5. **Visits before events.** The system expects a visit before any event from a user; events for a user with no prior visit are classified as organic. Visits come from the Web SDK, or, new, from the /visits endpoint.
6. **Send in real time; don't batch.** Send every event and visit as it happens, preferably within 30 minutes of the event occurring. Data that arrives later than 30 minutes after the end of the UTC day in which the event occurred is still accepted, but its event time is replaced with the receive time, which distorts attribution. Always send a timestamp. Note that the approximately 30-minute attribution delay you may read about is a separate, server-side hold on AppsFlyer's side, nothing for us to implement.
7. **Full server-side option (if we adopt visits).** With no Web SDK, our server owns the web user identifier: generate a stable ID for first-time visitors, persist it as a server-set first-party HTTP cookie (Set-Cookie header, not JavaScript; JS cookies are capped at approximately 7 days on Safari), reuse it on every request, and send it as user_id.appsflyer_id. The visit payload must include event_url (and should include ip, user_agent, http_referrer for attribution quality).
8. **SDK + S2S together.** If both send the same event, populate customer_dedup_id so AppsFlyer keeps one copy.
## Step 2: Build
1. Propose the design: new client/module, config (base URL, appId, API key storage in our secrets manager, never hardcoded), payload builders for events (and visits, if in scope), and the response/retry handling for 202.
2. After my approval, implement it following our existing conventions.
3. Map every field from the inventory through the payload mapping above; flag any field we currently send that has no new equivalent.
## Step 3: Validate
1. Send a test event (and visit, if in scope) and confirm a 202 response.
2. Verify the test data appears in the new web app in AppsFlyer (dashboard or Data Locker); this is the real success signal, not the HTTP response.
3. Confirm event names comply with the new constraints (1-64 chars, no @ = + -).
4. If running in parallel with the old service, compare event volumes between old and new for a few days before cutover, then decommission the old calls including setcuid.
Apéndice: resolución de fuentes de tráfico, PBA vs Medición de performance web
Si los valores de fuente de medios, canal o campaña son diferentes de los que mostraba PBA, aquí te explicamos por qué. Ambos utilizan el mismo enfoque: determinan la fuente de medios a partir de los parámetros de la URL y del referrer de la visita web, siguiendo una lista de prioridades hasta encontrar la primera coincidencia. Sin embargo, varias reglas han cambiado, y estos cambios afectan a los valores que aparecen en los reportes. Fuentes: Reglas de atribución de fuente de medios de PBA y Sobre la resolución de fuentes de tráfico.
Valores de fuente de medios renombrados
| Activador | Valor de PBA | Nuevo valor |
|---|---|---|
| Display/vídeo de Google (utm_source=Google + utm_medium= cpm / display/banner/video/listing) | doubleclick_int |
dv360_int |
| Twitter mediante UTM (twitter + cpc) | X Ads |
La medición de performance web también mapea más valores de PID a nombres para mostrar, por ejemplo, iossearchads_int a Apple Search Ads, metweb_int a Facebook Ads, twitterweb_int a Twitter, tiktokweb_int a tiktokglobal_int y snapweb_int a snapchat_int. Los reportes basados en los valores raw anteriores deben adaptarse a los nuevos valores.
Se amplía la cobertura de los Click IDs y se elimina dclid
PBA resolvía tres Click IDs: gclid como googleadwords_int, dclid como doubleclick_int y msclkid como bingsearch_int.
La medición de performance web resuelve muchos más: gclid/wbraid/gbraid como googleadwords_int, msclkid como bingsearch_int, twclid como Twitter, vmcid como yahoogemini_int, sccid como snapchat_int, li_fat_id como linkedin_int, ttclid como tiktokglobal_int, tbclid como taboola_int, ob_click_id/dicbo como outbrain_int, yclid como yandex_int y rdt_cid como reddit_int.
Advertencia
Hay dos cambios de comportamiento: dclid ya no se utiliza por sí solo para la resolución (PBA lo resolvía como doubleclick_int) y fbclid no se utiliza de forma explícita.
Se amplían las reglas personalizadas de UTM
El mapeo personalizado de utm_source + utm_medium es más amplio en la medición de performance web: incluye más sinónimos de medium (paid, paid_search, paid-search, etc.) y añade compatibilidad con TikTok, Snapchat y Pinterest, más allá de las reglas de PBA limitadas a un único medium. Cuando ninguna regla personalizada coincide, ambos utilizan como alternativa el valor raw de utm_source.
Channel
Los valores de canal también cambian de formato: de Direct / Organic search / Social media / Email / Ad / Referral / Other en PBA a los nuevos DIRECT / ORGANIC_SEARCH / SOCIAL_MEDIA / EMAIL / AD / REFERRAL / OTHER. Los filtros y las agrupaciones basados en las etiquetas anteriores deben actualizarse.