Przejdź do dokumentacji
SDK

Śledzenie otwarć i kliknięć

`emails.getTracking` i cały zasób `tracking`.

Jedna wiadomość

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)

Wiadomość, która nigdy nie była śledzona, rzuca OpenEmailApiError, którego isNotFound jest true, a nie pusty raport. „Nic nie zarejestrowaliśmy” i „nikt tego nie otworzył” to różne odpowiedzi i nie mogą mieć wspólnej odpowiedzi.

W całej skrzynce

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 i listClicks rozwiązują się do zwykłych tablic. get, listOpens i listClicks przyjmują albo identyfikator wysyłki msg_…, albo własny tmsg_… rekordu śledzenia.

Osobny zasób, a nie pola na emails, i powodem jest pokrycie: emails wymienia rekordy wysyłek, które istnieją tylko dla poczty obsłużonej przez to API. Kompozytor, narzędzia MCP i asystent wysyłają bez takiego rekordu, więc raport zbudowany na emails byłby raportem o Twoim ruchu w API, a nie o skrzynce.

Uczciwe czytanie liczb

ParaCo oznacza
`opens` / `clicks`Co ZASTOSOWANO: czy wiadomość wyszła z pikselem albo z przepisanymi linkami.
`opened` / `clicked`Co się wydarzyło.
`openCount`Liczone trafienia. Skanery i proxy prywatności wyłączone.
`openCountRaw`Wszystkie trafienia. Podawanie tego jako zaangażowania to sposób, w jaki wskaźnik otwarć przekracza 100%.
`attributable`Czy odczyt da się w ogóle przypisać do konkretnego, nazwanego odbiorcy.

Wskaźniki z tracking.getStats liczą się względem wiadomości ŚLEDZONYCH, nigdy względem wszystkiego wysłanego. Inaczej skrzynka śledząca jedną wiadomość na dziesięć wyglądałaby, jakby się załamała.

Parametry: tracking.list

openedboolean
`true` wybiera wiadomości z co najmniej jednym liczonym otwarciem, `false` wybiera wiadomości śledzone bez żadnego. Żadna z tych wartości nie jest domyślna, a `false` nigdy nie oznacza poczty nieśledzonej, która na tej liście w ogóle się nie pojawia.
clickedboolean
Ten sam filtr dla liczonych kliknięć, stosowany niezależnie od `opened`. Można podać oba, a wiadomości muszą spełnić oba.
daysnumber
Ile dni wstecz od teraz przeszukać, od 1 do 365, domyślnie 30; poza tym zakresem to 422. Okno mierzy się na czasie utworzenia rekordu śledzenia, a wymieniane są tylko rekordy, których wysyłka faktycznie wyszła.
limitnumber
Najwyżej tyle wiadomości, od 1 do 200, domyślnie 50, od najnowszych. Nie ma kursora: to raport w oknie czasowym, a nie strumień, więc jest ograniczony przez `days` i `limit` i czyta się go w całości.

Odpowiedź: TrackingResource

object'tracking'
Zawsze `'tracking'` na raporcie pobranym samodzielnie, przez `tracking.get`, `tracking.list` albo `emails.getTracking`. Ten sam raport zagnieżdżony jako `email.tracking` na pobranej wiadomości przychodzi bez tego klucza, bo tam jest częścią tamtego obiektu, a nie czymś, co pobrano.
idstring
Własny identyfikator rekordu śledzenia, `tmsg_…`. To na nim kluczowane są wywołania per trafienie, `listOpens` i `listClicks`; przekazany im `msg_…` jest najpierw rozwiązywany do niego.
sendIdstring | null
Wysyłka `msg_…`, z którą to koreluje, i null tam, gdzie nie zapisano rekordu wysyłki. Kompozytor, `sendEmail` z MCP i asystent wysyłają bez niego. Śledzenie obejmuje skrzynkę, a nie tylko ruch API.
threadIdstring | null
Wypełniane po transmisji, żeby interfejs do czytania mógł odnaleźć wiadomość, i null tam, gdzie sterownik nic nie zgłosił. Nie jest nośne: rekord z nullem tutaj i tak się liczy.
messageIdstring | null
Message-ID z RFC 5322, a nie nasz identyfikator. Także wypełniany po transmisji i null tam, gdzie transport nie zwrócił niczego, czym można by go wypełnić.
subjectstring | null
Temat w postaci z chwili wysyłki. Null na wiadomości zapisanej bez niego.
fromstring
Adres nadawczy, skopiowany na rekord, a nie dołączany z wysyłki. Raporty czyta się długo po fakcie, a adres od tego czasu poprawiony albo usunięty inaczej przepisywałby historię.
sourceEmailSource | (string & {})
Która powierzchnia ją wysłała: `composer`, `api`, `mcp`, `ai` albo `queue`. Typowane otwarcie, żeby powierzchnia, której ten SDK jeszcze nie nazywa, nie była zmianą łamiącą.
sentAtstring | null
Kiedy wiadomość poszła, jako instant ISO-8601. Null na rekordzie, którego wysyłka nigdy się nie zakończyła. `tracking.list` takie pomija, `get` nie.
opensboolean
Czy do tej wiadomości ZASTOSOWANO piksel. To, co zrobiono, a nie to, co mówi dziś ustawienie konta.
clicksboolean
Czy linki w tej wiadomości zostały przepisane. False, gdy treść nie niosła żadnych linków, bo wtedy nic nie zmieniono, a rekord twierdzący inaczej nie dałby się pogodzić z bajtami.
openedboolean
Czy zarejestrowano jakiekolwiek liczone otwarcie we wszystkich kopiach. Czytaj to razem z `opens`: brak danych, bo żadnych nie zbierano, to inny fakt niż to, że nikt wiadomości nie przeczytał.
clickedboolean
Czy zarejestrowano jakiekolwiek liczone kliknięcie. Mocniejszy dowód niż otwarcie, bo obrazy są blokowane o wiele częściej, niż linki pozostają nieodwiedzone.
attributableboolean
Czy każdy odczyt tutaj da się przypisać do nazwanego odbiorcy. False w chwili, gdy nieprzypisana kopia wykaże liczoną aktywność, czyli w przypadku wielu odbiorców, gdzie jedna treść idzie do całej listy pod jednym tokenem, więc sprawdź to, zanim napiszesz „Bob tego nie otworzył”.
openCountnumber
Otwarcia uznane za spowodowane przez człowieka, zsumowane po kopiach. Trafienia maszynowe są wyłączone, a powtórzenia w ciągu trzydziestu sekund zwijają się w jedno, więc to jest liczba do pokazania czytelnikowi.
clickCountnumber
Liczone kliknięcia, zsumowane po kopiach. Deduplikowane per link, a nie per wiadomość, więc dwa różne linki odwiedzone w odstępie sekund to dwa kliknięcia.
openCountRawnumber
Każde pobranie piksela, wraz ze skanerami i proxy prywatności. `openCountRaw - openCount` mówi, ile klasyfikator odłożył na bok, i jest jedynym dostępnym dowodem, że filtrowanie w ogóle się odbyło.
clickCountRawnumber
Każda wizyta na przepisanym linku, wraz z trafieniami maszynowymi i powtórzeniami.
firstOpenAtstring | null
Najwcześniejsze liczone otwarcie spośród kopii, null, dopóki go nie ma. Trafienia maszynowe nigdy nim nie ruszają.
lastOpenAtstring | null
Najnowsze liczone otwarcie spośród kopii, null, dopóki go nie ma.
firstClickAtstring | null
Najwcześniejsze liczone kliknięcie spośród kopii, null, dopóki go nie ma.
lastClickAtstring | null
Najnowsze liczone kliknięcie spośród kopii, null, dopóki go nie ma.
recipientsTrackingRecipientResource[]
Po jednym wpisie na każdą śledzoną kopię: per odbiorca tam, gdzie transport pozwala, by bajty różniły się dla każdej osoby, i jeden wspólny wpis tam, gdzie nie pozwala. Wspólny wpis jest pomijany, o ile faktycznie nic na nim nie wylądowało, więc nietknięty wiersz „ktoś” nigdy nie siedzi obok prawdziwych nazwisk.
recipients[].emailstring | null
Do kogo poszła ta kopia, małymi literami i w postaci z chwili wysyłki. Null dokładnie wtedy, gdy `attributed` jest false.
recipients[].kind'to' | 'cc' | 'bcc' | null
W którym nagłówku pojawił się adres, żeby raport czytał się tak, jak czytała się wiadomość. Null na kopii wspólnej, która nie należy do żadnego adresu.
recipients[].attributedboolean
Czy ten wiersz nazywa osobę. Czytaj go przed `email`: false to kopia wspólna, wymieniana, gdy tylko wyląduje na niej jakiekolwiek trafienie, a przypisanie nazwiska do tego trafienia, nawet w wiadomości z jednym odbiorcą, wymyśliłoby jedyny fakt, którego mechanizm nie potrafi dostarczyć.
recipients[].openCountnumber
Liczone otwarcia wyłącznie na tej kopii, przy tych samych wyłączeniach co suma dla wiadomości: trafienia maszynowe odrzucone, a powtórzenia w ciągu trzydziestu sekund zwinięte w jedno.
recipients[].clickCountnumber
Liczone kliknięcia wyłącznie na tej kopii, deduplikowane per link, a nie per kopia.
recipients[].firstOpenAtstring | null
Najwcześniejsze liczone otwarcie na tej kopii, null, dopóki go nie ma.
recipients[].lastOpenAtstring | null
Najnowsze liczone otwarcie na tej kopii, null, dopóki go nie ma.
recipients[].firstClickAtstring | null
Najwcześniejsze liczone kliknięcie na tej kopii, null, dopóki go nie ma.
recipients[].lastClickAtstring | null
Najnowsze liczone kliknięcie na tej kopii, null, dopóki go nie ma.
linksTrackingLinkResource[]
Każdy link przepisany w tej wiadomości, w kolejności, w jakiej stał w treści. Pusta lista tam, gdzie nie było żadnych: wiadomość wysłana z wyłączonym `clicks` albo taka, której treść nie zawierała w ogóle linku.
links[].idstring
Własny identyfikator linku, `lnk_…`. To wartość, którą nazywa `linkId` w wierszu kliknięcia, więc trafienie z `listClicks` da się dopasować z powrotem do wpisu tutaj.
links[].urlstring
Dokąd link faktycznie prowadzi, w postaci sprzed przepisania, taki jak był w wiadomości. Przekierowujący rozwiązuje identyfikator z powrotem do tego adresu i odsyła tam odwiedzającego.
links[].labelstring | null
Tekst odnośnika w postaci, w jakiej pojawił się w wiadomości, albo null, gdy link go nie miał, na przykład przy obrazie albo gołym adresie URL. Jest po to, by raport mógł napisać „link do cennika”, zamiast cytować URL z trzema parametrami śledzącymi, i nigdy nie zastępuje `url`.
links[].clickCountnumber
Liczone wizyty na tym linku, zsumowane po kopiach. To samo trzydziestosekundowe okno per link co przy `clickCount` na wiadomości.
links[].clickCountRawnumber
Każda wizyta na tym linku, wraz z trafieniami maszynowymi i powtórzeniami.