Shopify checkout_contact_info_submitted event always returns null email and phone fields

Issue

I’m implementing Shopify’s Web Pixels Extension and tracking the checkout_contact_info_submitted event. However, the email and phone fields in the checkout object are always empty/undefined, even though users have just submitted this information on the checkout form.

Current Code

analytics.subscribe(
  'checkout_contact_info_submitted',
  ({ data: { checkout } }) => {
    const { email, phone } = checkout
    
    // email and phone are always null
  }
)

Expected Behavior

Since the event is specifically checkout_contact_info_submitted, I expected the checkout object to contain the contact information (email, phone) that was just submitted.

Questions

  • Is this expected behavior from Shopify’s Web Pixels Extension API?
  • Are these fields supposed to be available at a different time or location in the checkout object?
  • Is there a different approach to capture customer email and phone during checkout?
  • Are there any plans to expose these fields in the checkout object for this event?

I’m not certain if the permission is required but this could be down to Protected Customer Data, have you got access to this?

Thanks, Luke. I don’t currently have Protected Customer Data permission.

If we already have access to Web Pixel events, is that not enough to receive email and phone on checkout_contact_info_submitted?

I’m also certain we were able to see both fields up until February, so this looks like a recent change/regression in the event payload behavior.

Also All i need is customer ID is there a way to only get that?

Hi Joseph,

This is expected behavior following the Protected Customer Data policy enforcement that went into effect on December 10, 2025. That lines up with the timeline you mentioned — things were unredacted until around February, which is when you would have started seeing the impact.

Since that date, personally identifiable information (PII) in web pixel event payloads — including email, phone, first_name, and address fields — is filtered at runtime based on the app’s approved protected customer data scopes. If your app hasn’t been approved for the corresponding scope, those fields will be null.

The scopes relevant to your use case:

  • read_customer_email — required to receive email
  • read_customer_phone — required to receive phone
  • read_customer_personal_data — broader scope covering general PII

To restore access:

  1. Review which protected scopes your app needs in the Protected Customer Data Policy documentation.
  2. Submit a request for the scopes you require. Only request the ones your app actually uses.
  3. Once approved, the fields will populate in your event payloads automatically — no code changes needed on your end.

Regarding your follow-up question about customer ID: you can access it in two places:

  • Init data — via init.data.customer.id, available when the pixel initializes for authenticated (logged-in) customers.
  • checkout_completed event — via data.checkout.order.customer.id in the event payload, available for both authenticated and guest checkouts.

In the meantime, make sure your event handlers are resilient to null values for any PII fields.

Hi Emile,

Hope you are having a wonderful day. Thanks for the update, this is really helpful context.

I have four quick questions for clarification:

  1. To confirm, the request I need to submit is the Protected Customer Data access request, correct?

  2. Will I still be able to access the customer ID even without Protected Customer Data scope approval?

  3. Is there a way to access the customer ID before checkout (for example earlier in the customer journey)? I know this may be slightly separate from the current topic, but it would be very helpful for us.

  4. If possible, could you share code snippets for getting the customer ID in both cases you mentioned (init.data.customer.id and checkout_completed event)?
    Thanks again for the guidance.
    Best,
    Joseph

Thanks for the kind words! Happy to help clarify. Here are your answers:

1. Yes, the request you need to submit is the Protected Customer Data access request. You’ll select which specific scopes you need (e.g. read_customer_email, read_customer_phone, etc.) as part of that process.

2. Yes, customer ID is not gated behind Protected Customer Data scopes. It is not considered PII, so it will be available regardless of your app’s approval status.

3. You can access the customer ID earlier in the journey via the pixel’s init data — specifically init.data.customer.id. However, this is only populated for authenticated (logged-in) customers. For guest checkouts, the customer ID won’t be available until the checkout_completed event.

4. Here are code snippets for both approaches:

From init data (available at pixel initialization, authenticated customers only):

shopify.extend('WebPixel::Render', (api) => {
  const customerId = api.init.data.customer?.id;

  if (customerId) {
    // Customer is logged in — use the ID
  }
});

From the checkout_completed event (available for both authenticated and guest checkouts):

api.analytics.subscribe('checkout_completed', (event) => {
  const customerId = event.data.checkout.order?.customer?.id;

  if (customerId) {
    // Use the customer ID
  }
});

Hope that helps!

1 Like