guides
Email tracking pixels
Create email tracking pixels with MailSlurp, detect opens, receive webhook events, and inspect recipient activity through the API or dashboard.

A tracking pixel is a tiny remote image with a unique URL. When an email client requests that URL, MailSlurp marks the pixel as seen and can send an EMAIL_OPENED webhook. You can also inspect the event through the API or the open tracking dashboard.
That description has one important wrinkle: the event proves that the image URL was requested. It does not prove that a person read, understood, or acted on the email. Pixels are handy little doorbells, but they cannot tell you who walked through.
Choose automatic or standalone tracking
MailSlurp gives you two useful ways to create a pixel:
- Add one while sending. Set
addTrackingPixel: truewhen MailSlurp sends the HTML email and should keep the message and pixel connected. The sent-email record contains one or morepixelIds. - Create one yourself. Call
createTrackingPixelwhen you need pixel HTML or a URL for a template, another sending system, or an isolated test. The result containsid,html,url,seen, and optional recipient details.
Use a distinct pixel for each message or recipient you need to identify. Reusing one URL across a whole list can tell you that somebody or something requested it, but not which delivery produced the request.
Keep API keys on a trusted server, test runner, or secret-managed CI worker. A pixel URL is designed to be requested by an email client, so treat that URL as public and avoid placing private data in it.
Create a standalone tracking pixel
The current TypeScript client expects an options object inside createTrackingPixel. Give the pixel a useful name and, when appropriate, the intended recipient so later inspection is less like rummaging through an unlabeled drawer.
import { MailSlurp } from 'mailslurp-client'
async function createPixel() {
const apiKey = process.env.MAILSLURP_API_KEY
if (!apiKey) throw new Error('Set MAILSLURP_API_KEY')
const mailslurp = new MailSlurp({ apiKey })
const pixel = await mailslurp.trackingController.createTrackingPixel({
createTrackingPixelOptions: {
name: 'September onboarding message',
recipient: 'reader@example.com',
},
})
console.log(pixel.id)
console.log(pixel.html)
}
createPixel().catch((error) => {
console.error(error)
process.exitCode = 1
})
Insert pixel.html into the HTML body that will be delivered to that recipient. Do not add it to a plain-text part: plain text cannot load an image. If your templating system sanitizes remote images, inspect the final delivered HTML rather than assuming the source template survived unchanged.
Send an email and verify its pixel
For MailSlurp-sent email, addTrackingPixel: true is the shorter path. This complete check creates a sender and recipient, sends an HTML message, finds the generated pixel, requests its URL deliberately, and verifies the state change. The deliberate fetch tests the mechanism; it is not presented as a human open.
import { MailSlurp } from 'mailslurp-client'
async function verifyTrackedEmail() {
const apiKey = process.env.MAILSLURP_API_KEY
if (!apiKey) throw new Error('Set MAILSLURP_API_KEY')
const mailslurp = new MailSlurp({ apiKey })
const sender = await mailslurp.createInbox()
const recipient = await mailslurp.createInbox()
try {
const sent = await mailslurp.inboxController.sendEmailAndConfirm({
inboxId: sender.id,
sendEmailOptions: {
to: [recipient.emailAddress],
subject: 'Tracking pixel check',
body: '<html><body><h1>Hello</h1><p>Welcome aboard.</p></body></html>',
isHTML: true,
addTrackingPixel: true,
},
})
const pixelId = sent.pixelIds?.[0]
if (!pixelId) throw new Error('The sent email did not contain a pixel ID')
const before = await mailslurp.trackingController.getTrackingPixel({
id: pixelId,
})
if (before.seen) throw new Error('Expected the new pixel to be unseen')
const response = await fetch(before.url)
if (!response.ok) throw new Error(`Pixel returned ${response.status}`)
const after = await mailslurp.trackingController.getTrackingPixel({
id: pixelId,
})
if (!after.seen) throw new Error('Expected the request to mark the pixel seen')
} finally {
await Promise.all([
mailslurp.deleteInbox(sender.id),
mailslurp.deleteInbox(recipient.id),
])
}
}
verifyTrackedEmail().catch((error) => {
console.error(error)
process.exitCode = 1
})
Turn that sequence into a test in your preferred runner. Use a unique subject, assert the sent record contains a pixel ID, and clean up test inboxes even when an assertion fails. For a customer journey, keep going: receive the delivered email, inspect its content and links, then complete the reset, sign-in, invoice, or onboarding action the message exists to support.
Receive open events with webhooks
Polling getTrackingPixel is useful for a focused test or occasional inspection. A webhook is better when your application should react as events arrive. Subscribe to EMAIL_OPENED through MailSlurp email webhooks. The payload includes identifiers for the webhook, inbox, pixel, sent email, and recipient, plus its creation time.
Treat webhook delivery like any other distributed event:
- verify the request using the webhook controls your integration requires;
- store the payload
messageIdand make processing idempotent; - return a successful response promptly, then move slower work to a queue;
- keep retries from sending the same follow-up twice; and
- log the pixel and sent-email IDs so a support engineer can trace the event without guessing.
Avoid using an open event as the sole permission for an irreversible or sensitive action. Privacy loading and automated scanners can request remote content before the recipient chooses to do anything. A click, authenticated session, reply, or completed product action is a sturdier gate.
Understand false positives and missed opens
A seen pixel is real network activity, but the actor behind it may be less obvious. Apple Mail Privacy Protection can load remote content privately and automatically. Gmail serves images through secure proxy servers, hiding details such as the reader's device and location. Corporate security systems and preview tools can also fetch remote content.
The reverse happens too. A real reader may use plain text, block remote images, read while offline, or view a client that never requests the pixel. Forwarding can produce another request tied to the original tracked message. Caching can change how repeated views appear.
That is why the email open rate guide describes opens as a directional signal. Read them beside successful delivery, inbox placement, clicks, replies, complaints, unsubscribes, and the customer action you hoped the email would make easier.
Troubleshoot a pixel that looks wrong
If the sent record has no pixel ID, confirm the message is HTML and that addTrackingPixel reached the final send options. Inspect the sent record and delivered HTML instead of only the template source.
If the pixel stays unseen, check whether the delivered HTML contains its URL, whether remote images are enabled, and whether a proxy or content-security rule can reach the asset. A controlled MailSlurp inbox helps you separate template and delivery problems from a recipient's local client settings.
If the pixel becomes seen before a person could reasonably open the email, investigate privacy preloading, security scanning, automated previews, and test code that may have fetched the URL. Do not quietly relabel that event as human engagement.
If webhook work happens twice, compare payload messageId values and fix the receiver's idempotency before adding more automation. Retries are normal; duplicated customer messages do not have to be.
Test the whole message, not only the pixel
Open tracking is one instrument on the bench. Before relying on it in a real email journey:
- Deliver the actual template to a controlled MailSlurp inbox.
- Confirm the sender, subject, HTML, text fallback, links, and unsubscribe path.
- Use device previews to inspect the clients your readers use.
- Run an inbox placement test when the sender or campaign changed.
- Test the
EMAIL_OPENEDwebhook with retries and duplicate delivery. - Complete the intended customer action and keep that result separate from the open signal.
For recurring sends, Campaign Probe can watch links and images over time. Domain Monitor covers sender-authentication drift, while Email Audit helps with a focused pre-send review. Each tool answers a different question; the useful picture comes from putting them together.
Common questions
Can a tracking pixel prove that one person read an email?
No. It can tie a remote-image request to a tracked pixel and, when configured, an intended recipient. Privacy services, proxies, scanners, forwarding, caching, and blocked images prevent that request from being reliable proof of human reading or understanding.
Do tracking pixels work in plain-text email?
No. A plain-text message cannot embed a remote image. Send an honest text alternative for readers who prefer it, but do not expect that part to generate a pixel event.
Should I use one pixel for every recipient?
Use a distinct pixel for each message or recipient you need to distinguish. A shared pixel can confirm that its URL was requested, but it throws away the association that makes the result useful.
What should an open event trigger?
Use it for observation, reporting, or a low-risk follow-up that tolerates an automated request. Require a stronger signal for sensitive actions. A verified click, authenticated visit, reply, or completed workflow is usually a better decision point.
What privacy steps should I take?
Collect only what the message needs, explain your use of tracking, limit access and retention, and follow the privacy and consent rules that apply to your recipients and location. Never infer precise identity, location, consent, or intent from one image request.
Keep the signal honest
MailSlurp makes the mechanics pleasantly small: create a pixel or add one during send, keep its ID, inspect seen, and receive EMAIL_OPENED events when you need them. The thoughtful part is interpretation. Call a request a request, test the message people actually receive, and let the customer's completed journey have the last word.