Ir a la documentación
SDK

Seguimiento de aperturas y clics

`emails.getTracking` y todo el recurso `tracking`.

Un mensaje

tracking.ts
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

tracking-report.ts
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

ParQué 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.