Seguimiento de aperturas y clics
`emails.getTracking` y todo el recurso `tracking`.
Un mensaje
const report = await openemail.emails.getTracking('msg_…') console.log(report.openCount, 'opens from', report.recipients.length, 'recipients')for (const link of report.links) console.log(link.url, link.clickCount)Un mensaje del que nunca se hizo seguimiento lanza un OpenEmailApiError cuyo isNotFound es true, no un informe vacío. «No registramos nada» y «nadie lo abrió» son respuestas distintas y no deben compartir una misma respuesta.
En todo el buzón
await openemail.tracking.list({ opened: false, days: 7, limit: 100 })await openemail.tracking.getStats({ days: 30, offsetMinutes: -new Date().getTimezoneOffset() })await openemail.tracking.get('msg_…')await openemail.tracking.listOpens('msg_…', { includeMachine: true })await openemail.tracking.listClicks('msg_…')list, listOpens y listClicks se resuelven en arrays simples. get, listOpens y listClicks aceptan tanto el id de envío msg_… como el tmsg_… propio del registro de seguimiento.
Es un recurso propio en lugar de campos en emails, y el motivo es la cobertura: emails lista registros de envío, que solo existen para el correo que gestionó esta API. El redactor, las herramientas MCP y el asistente envían sin uno, así que un informe construido sobre emails sería un informe sobre tu tráfico de API y no sobre el buzón.
Leer las cifras con honestidad
| Par | Qué significa |
|---|---|
| `opens` / `clicks` | Lo que se APLICÓ: si el mensaje salió con un píxel o con enlaces reescritos. |
| `opened` / `clicked` | Lo que ocurrió. |
| `openCount` | Visitas contabilizadas. Se excluyen los escáneres y los proxies de privacidad. |
| `openCountRaw` | Todas las visitas. Citar esto como interacción es la forma de que una tasa de apertura supere el 100 %. |
| `attributable` | Si una lectura puede atribuirse siquiera a un destinatario concreto. |
Las tasas de tracking.getStats se calculan sobre los mensajes CON SEGUIMIENTO, nunca sobre todo lo enviado. De lo contrario, un buzón que hace seguimiento de uno de cada diez mensajes parecería haberse hundido.
Parámetros: tracking.list
openedboolean- `true` selecciona los mensajes con al menos una apertura contabilizada; `false` selecciona los mensajes con seguimiento que no tienen ninguna. Ninguno es el valor por defecto, y `false` nunca significa correo sin seguimiento, que no aparece en esta lista en absoluto.
clickedboolean- El mismo filtro para los clics contabilizados, aplicado con independencia de `opened`. Se pueden indicar ambos, y los mensajes deben cumplir los dos.
daysnumber- Cuántos días hacia atrás desde ahora hay que mirar, de 1 a 365 y con 30 por defecto; fuera de ese rango es un 422. La ventana se mide sobre la fecha de creación del registro de seguimiento, y solo se listan los registros cuyo envío salió realmente.
limitnumber- Como máximo este número de mensajes, de 1 a 200 y con 50 por defecto, de más nuevo a más antiguo. No hay cursor: esto es un informe sobre una ventana y no un feed, así que está acotado por `days` y `limit` y se lee entero.
Respuesta: TrackingResource
object'tracking'- Siempre `'tracking'` en un informe obtenido por sí mismo, mediante `tracking.get`, `tracking.list` o `emails.getTracking`. El mismo informe anidado como `email.tracking` en un mensaje recuperado llega sin esta clave, porque allí forma parte de ese objeto en lugar de ser algo que se obtuvo.
idstring- El id propio del registro de seguimiento, `tmsg_…`. Es la clave sobre la que operan las llamadas por visita `listOpens` y `listClicks`; un `msg_…` que se les entregue se resuelve antes a este.
sendIdstring | null- El envío `msg_…` con el que se correlaciona, y null cuando no se escribió ningún registro de envío. El redactor, el `sendEmail` de MCP y el asistente envían todos sin uno. El seguimiento cubre el buzón, no solo el tráfico de la API.
threadIdstring | null- Se rellena tras la transmisión para que una interfaz de lectura pueda volver a encontrar el mensaje, y es null cuando el driver no informó de ninguno. No es imprescindible: un registro con este campo en null sigue contando.
messageIdstring | null- El Message-ID de RFC 5322, no nuestro id. También se rellena tras la transmisión, y es null cuando el transporte no devolvió nada con lo que rellenarlo.
subjectstring | null- El asunto tal como estaba en el momento del envío. Null en un mensaje registrado sin ninguno.
fromstring- La dirección de envío, copiada en el registro en lugar de unida desde el envío. Los informes se leen mucho después, y una dirección corregida o eliminada desde entonces reescribiría la historia.
sourceEmailSource | (string & {})- Qué superficie lo envió: `composer`, `api`, `mcp`, `ai` o `queue`. Con tipo abierto para que una superficie que este SDK aún no nombra no sea un cambio incompatible.
sentAtstring | null- Cuándo salió el mensaje, como instante ISO-8601. Null en un registro cuyo envío nunca se completó. `tracking.list` los excluye; `get` no.
opensboolean- Si se APLICÓ un píxel a este mensaje. Esto es lo que se hizo, no lo que dice ahora la configuración de la cuenta.
clicksboolean- Si se reescribieron los enlaces de este mensaje. False cuando el cuerpo no llevaba enlaces, porque entonces no se cambió nada y un registro que afirmara lo contrario no se podría conciliar con los bytes.
openedboolean- Si se registró alguna apertura contabilizada entre las copias. Léelo junto con `opens`: que no haya datos porque no se recogió ninguno es un hecho distinto de que nadie haya leído el mensaje.
clickedboolean- Si se registró algún clic contabilizado. Es una prueba más sólida que una apertura, ya que las imágenes se bloquean mucho más a menudo de lo que los enlaces se quedan sin seguir.
attributableboolean- Si toda lectura recogida aquí puede atribuirse a un destinatario concreto. Es false en cuanto una copia sin atribuir muestra actividad contabilizada, que es el caso de varios destinatarios en el que un mismo cuerpo va a toda la lista bajo un único token, así que compruébalo antes de escribir «Bob no ha abierto esto».
openCountnumber- Aperturas que se cree causadas por una persona, sumadas sobre las copias. Se excluyen las visitas de máquinas y las repeticiones en menos de treinta segundos se agrupan en una, así que esta es la cifra que hay que poner delante de un lector.
clickCountnumber- Clics contabilizados, sumados sobre las copias. Se deduplican por enlace y no por mensaje, así que dos enlaces distintos seguidos con segundos de diferencia son dos clics.
openCountRawnumber- Todas las peticiones del píxel, incluidos los escáneres y los proxies de privacidad. `openCountRaw - openCount` es cuántas apartó el clasificador, y la única prueba disponible de que el filtrado llegó a ocurrir.
clickCountRawnumber- Todas las visitas a un enlace reescrito, incluidas las de máquinas y las repeticiones.
firstOpenAtstring | null- La primera apertura contabilizada entre las copias, y null mientras no haya ninguna. Las visitas de máquinas nunca la mueven.
lastOpenAtstring | null- La apertura contabilizada más reciente entre las copias, null mientras no haya ninguna.
firstClickAtstring | null- El primer clic contabilizado entre las copias, null mientras no haya ninguno.
lastClickAtstring | null- El clic contabilizado más reciente entre las copias, null mientras no haya ninguno.
recipientsTrackingRecipientResource[]- Una entrada por copia con seguimiento: una por destinatario cuando el transporte permite que los bytes difieran por persona, y una única entrada compartida cuando no. La entrada compartida se descarta salvo que realmente haya llegado algo a ella, así que una fila «alguien» sin tocar nunca aparece junto a nombres reales.
recipients[].emailstring | null- A quién fue esta copia, en minúsculas y tal como estaba en el momento del envío. Es null exactamente cuando `attributed` es false.
recipients[].kind'to' | 'cc' | 'bcc' | null- En qué cabecera apareció la dirección, para que un informe se lea igual que se leyó el mensaje. Null en la copia compartida, que no pertenece a ninguna dirección.
recipients[].attributedboolean- Si esta fila nombra a una persona. Léelo antes que `email`: false es la copia compartida, que se lista en cuanto le llega cualquier visita, y ponerle un nombre a esa visita, incluso en un mensaje con un solo destinatario, inventaría el único dato que el mecanismo no puede aportar.
recipients[].openCountnumber- Aperturas contabilizadas solo en esta copia, con las mismas exclusiones que el total del mensaje: se descartan las visitas de máquinas y las repeticiones en menos de treinta segundos se agrupan en una.
recipients[].clickCountnumber- Clics contabilizados solo en esta copia, deduplicados por enlace y no por copia.
recipients[].firstOpenAtstring | null- La primera apertura contabilizada en esta copia, null mientras no haya ninguna.
recipients[].lastOpenAtstring | null- La apertura contabilizada más reciente en esta copia, null mientras no haya ninguna.
recipients[].firstClickAtstring | null- El primer clic contabilizado en esta copia, null mientras no haya ninguno.
recipients[].lastClickAtstring | null- El clic contabilizado más reciente en esta copia, null mientras no haya ninguno.
linksTrackingLinkResource[]- Todos los enlaces que se reescribieron en este mensaje, ordenados por su posición en el cuerpo. Vacío cuando no hubo ninguno: un mensaje enviado con `clicks` desactivado, o uno cuyo cuerpo no llevaba ningún enlace.
links[].idstring- El id propio del enlace, `lnk_…`. Es el valor que nombra el `linkId` de una fila de clic, de modo que una visita de `listClicks` puede emparejarse con la entrada de aquí.
links[].urlstring- Adónde va realmente el enlace, tal como estaba en el mensaje antes de la reescritura. El redirector resuelve un id de vuelta a esto y envía al visitante a su destino.
links[].labelstring | null- El texto del enlace tal como apareció en el mensaje, o null cuando el enlace no tenía ninguno, como una imagen o una URL escueta. Está ahí para que un informe pueda decir «el enlace de precios» en lugar de citar una URL con tres parámetros de seguimiento, y nunca sustituye a `url`.
links[].clickCountnumber- Visitas contabilizadas a este enlace, sumadas sobre las copias. La misma ventana de treinta segundos por enlace que `clickCount` en el mensaje.
links[].clickCountRawnumber- Todas las visitas a este enlace, incluidas las de máquinas y las repeticiones.