/
Tech Refinement - Reduce Delivery Address Errors

Tech Refinement - Reduce Delivery Address Errors

This refinement is intended to clarify and evaluate possible fixes to the main problems associated with the store location page in wl-app, as identified by the UX team.

Issue 2 - Unintentional city change

In the confirm your address page, in some cases, the city can change after the customer inputs a street number.

image-20240814-152234.png
Search in “Calle De nuestra senora de guadalupe” street

Why?

The store locator uses Google’s Places Auto Complete API to identify the customer’s address. In cases where different places have the same name in different cities, the algorithm might consider that street number 3 is more likely in city A, but street number 10 is more likely in city B.

Improvement Ideas?

Add warning explicitly showing that the city has changed

DeliveryErrors-change-city-modal.webm
Change city warning modal example

Pros

Cons

Pros

Cons

Very simple and fast

Addresses problems specific to store locator changing cities, but not smaller changes in address

Limit results to a certain distance from the first selection

Google’s API doesn’t allow us to explicitly set a limit to a city, but it does allow us to restrict the result to be within a certain radius of a geo coordinate. This option suggests that, after the customer selects an address in the search bar, changes in the form (street number) will be limited to a certain radius of the original result. The customer can reset the search by going back to the search page.

One challenge in this option is how to fine-tune the radius. For example: is a 10 km radius a good enough value to not allow results in another city, but still identify all numbers that belong to that street? A safer alternative is biasing the result to be close to the first guess instead of hard limiting it to a value. After preliminary tests, this achieved the same results:

Pros

Cons

Pros

Cons

Very simple and fast

If the customers want to change the city in the delivery form, but the address already matches an address on the current city, they won’t know they should go back to the previous page and search again

Issue 3 - Street Name change is not updated in the system

In the “confirm your address” page, the customer has the option to change the street name, however, changes in this field neither update the geo-coordinates, nor the zip code in the address.

Why?

This one is more complicated, but in summary, an update in the street name field is set up to not update any of the other address components, including the geo-coordinates. More specifically, any Google Maps request that returns an addressLine1 (street concatenated with street number) different from the one chosen by the customer in the previous screen will be ignored.

To be clear, any update in the street name is included in the backend and is sent to the delivery partner (DMP, Homeria), however, its value is inconsistent with the rest of the address (street that doesn’t match postal code and number). Another impact is that the restaurant for delivery is decided based solely on the distance calculated using geo-coordinates, so the wrong restaurant might receive the order.

Improvement Ideas?

Disable or remove the street name input

Given that the customer has already chosen the street name in the previous address, hiding this field in the confirmation page is an option to prevent inconsistencies in the address.

Pros

Cons

Pros

Cons

Simple and fast

Avoids mismatch in backend restaurant selection

Customers have to return to the previous page if they want to change the street name

Multi step form

Although the removal of the street number is the quickest and easiest solution, it would impact markets such as the UK where the search by ZIP code is the main method of search. A more complete solution is refactoring the form to work in more than one step and improve validations and map predictions. The image below displays how this page could work but is by no means a final design:

In screen 1, the user will type their address and click on one item from the drop-down. After the click, if the address selected includes a street name the user will be redirected to screen 2 where they can type the street name and click on next to be redirected to screen 3. However, if the address already contains a street number, the customer is redirected straight to screen 3. Screen 4 works as a confirmation page where the customer can double check the address.

The main advantage of breaking the form in more than one step is that now the app can only call the autocomplete service when the customer clicks in next, making sure that the coordinates are updated and allowing the app to securely make more validations. With this form, we no longer need to include a bias in the query because the form can check if the city changed, as well as display clear warnings if the address is not found by Google’s API.

Pros

Cons

Pros

Cons

Separates user input from autocomplete predictions.

Assures the coordinates always match the customer address.

Higher effort compared to other alternatives, but still manageable within a sprint.

Increases friction to select a restaurant.

Impact on FT

Currently the input fields are defined as a Formik form in the middle of delivery-address-form.tsx,

<AddressWrapper> {HIDE_STREET_NAME_IN_DELIVERY_FORM ? ( <MultiStepAddressForm address={addressComponents} coordinates={coordinates} getDetailsPlaceData={getDetailsPlaceData} setDeliveryInstructions={setDeliveryInstructions} setPlaceId={setPlaceId} /> ) : ( <Formik initialValues={{ streetName: addressComponents?.route, streetNumber: addressComponents?.streetNumber, }} onSubmit={() => { // maybe refactor this and have everything handled by formik instead? }} > {() => ( <> {!HIDE_STREET_NAME_IN_DELIVERY_FORM && ( <Field name="streetName" component={FormikTextInput} required label={formatMessage({ id: 'deliveryAddressStreetName' })} data-testid="delivery-street-name-input" value={addressComponents?.route} onChange={handleStreetNameChange} /> )} <FieldWrapper> <Field name="streetNumber" component={FormikTextInput} required label={formatMessage({ id: 'deliveryAddressStreetNumber' })} data-testid="delivery-street-number-input" value={addressComponents?.streetNumber} onChange={handleStreetNumberChange} /> {enableRequireAddress2 ? ( <Field name="instructions" component={FormikTextInput} label={formatMessage({ id: 'deliveryAddressLine2' })} data-testid="delivery-instructions-input" value={deliveryInstructions} onChange={handleDeliveryInstructionsChange} /> ) : ( <Field name="addressLine2" component={FormikTextInput} label={formatMessage({ id: 'deliveryAddressLine2' })} data-testid="delivery-address-line2-input" value={addressComponents?.addressLine2} onChange={handleAddressLine2Change} /> )} </FieldWrapper> {enableSavedAddressesImprovements && ( <> <AddressNameLabel> {formatMessage({ id: 'saveThisAddressLabel' })} </AddressNameLabel> <Field name="name" component={FormikTextInput} value={addressComponents?.alias} onChange={handleAddressNameChange} data-testid="delivery-address-name-input" label={formatMessage({ id: 'saveThisAddressPlaceholder' })} /> </> )} </> )} </Formik> )} </AddressWrapper>

To improve this code and make sure the enableSavedAddressesImprovements works in both scenarios, we have to create a new component delivery-address-formik-form.tsx (TBD), which be used both in the current form and the multi-step form.

Splitting API and Form data structures

The main problem preventing the customer from updating the coordinates whenever the street name changes or for the unintentional city change is that both the predictions API results and the customer input are stored in the same React state. As such, splitting them would allow us to constantly update the address whenever the customer types new information, but at the cost that might be a mismatch between the address in the form and the API result.

Splitting this information would require us refactoring delivery-address-form.tsx, or more precisely, split it into reusable components and create a new form with split states, where we can control which form is used via feature toggle. However, this poses a problem of what do we do if they don’t match?

Option A - Ask if customer wants to proceed with unrecognized address

In the example below we can see a POC where the customer types an address that doesn’t exist (Calle de nuestra señora guadalupe 12345). This address is not recognized by the autocomplete API, so when the customer clicks on deliver here, a warning appears asking for confirmation. In this case, the coordinates used will be the last successful prediction returned by the API, so this isn’t a viable solution as it doesn’t solve the core problem.

Option B - Ask if customer to pin address on map if unrecognized address

WIP

Refactoring plan

  • Create a new component for the Pinned location

  • Create a new component for the form input

    • should include the ENABLE_SAVED_ADDRESSES_IMPROVEMENTS FT

    • should include the ENABLE_DELIVERY_DETAILS_FORM_REQUIRE_ADDRESS_2 FT

  • Create new form component with split data structures

  • Include ENABLE_PERSIST_ADDRESS_ON_STORE_SELECTOR FT logic the new form

  • Include ENABLE_SAVE_DELIVERY_ADDRESS FT logic the new form

  • Include ENABLE_SAVED_ADDRESSES_IMPROVEMENTS FT logic the new form

  • Include ENABLE_RECENT_ADDRESSES FT logic the new form

  • Include ENABLE_DELIVERY_SPLIT_ADDRESS_DETAILS FT logic the new form

    • TBC this flag appears to be true for all markets, confirm if it is waiting form removal

  • Include ENABLE_DELIVERY_SHOW_ONLY_STREET_NAME_AND_NUMBER FT logic the new form

    • TBC it requires ENABLE_DELIVERY_SPLIT_ADDRESS_DETAILS to be off to have any impact

  • Include ENABLE_MAP_FALLBACK FT logic the new form

    • TBC this feature appears to be deprecated

  • Include ENABLE_DELIVERY_ADDRESS_ON_SAME_SCREEN FT logic the new form

  • Include ENABLE_DELIVERY_GEOLOCATION_2 FT logic the new form

  • Include ENABLE_DELIVERY_DETAILS_FORM_REQUIRE_ADDRESS_2 FT logic the new form

 

A/B Testing

Since selecting the restaurant is a critical operation and can impact order conversion numbers, it is extremely important to measure the impact these changes will have on the user experience. As such, a good idea is to activate the new changes for a relatively small subset of customers (eg. 20%) and create a new amplitude conversion chart to monitor the results.

What will we measure? We’ll validate the percentage of users that after accessing “/store-locator/address”. Additionally we’ll measure:

  • Average time between events

  • Average number of “Manual location search” events (TBC)

  • If alternative solution is chosen:

    • Average number of “Button Click” events between start and finish

page proceed to click on the button “Deliver Here”

Just as an example, this funnel allow to compare the conversion rate for EN and ES speaking customer between the two events aforementioned. We can do the same with the value of the FT if we include it on the user attributes (INTL already does this type of A/B testing, we just need to align the process).

Similarly the funnel can be used to compute the average time between events:

 

Anexus

Possible issue - Homeria map showing different location than RBI

One possible issue that Paula mentioned is that Homeria shows a different location on their map than RBI. For a quick validation I made an order in BK PT Staging:

This is the max zoom that the BK PT Staging will allow me to use, and it is not close enough to get a precise location. After accessing their system I can confirm they are receiving the same coordinates from their API:

I could ascertain that both systems are using the same coordinates and addresses. Given that the map feature is not working in their dev environment and BK PT map doesn’t give me more details, this is as far as I can go without more information.

Filtering by city/zip on autocomplete dropdown

This section explored the possibility of filtering the location predictions shown in the autocomplete dropdown to only include results in the same city or zip code. Currently, whenever the autocomplete logic is running, Google’s places autocomplete service is called and the predictions are displayed.

Ideally, we’d like the API to do the filtering for us, however, as it can be seen from the documentation, the only options to restrict results are:

  • Country

  • Language

  • Types (e.g. address, establishment, …)

Given that this is not an option, the next step would filter the predictions returned by the API, however, the predictions by themselves don’t give us a lot to filter by (see AutocompletePrediction). The two fields that could be used are:

  • main_text: This is the main text part of the unformatted description of the place suggested by the Places service. Usually the name of the place.

  • secondary_text: This is the secondary text part of the unformatted description of the place suggested by the Places service. Usually the location of the place.

Neither of them is guaranteed to include the city (although in most cases it will), and never include a zip code. The remaining option would be to call another API to reverse geocode the results and get the necessary information.

This already happens today, but only when the customer clicks on one of the items listed in the dropdown which meaningfully reduces the number of calls. The diagram below displays the flow, with the green loop showing the added calls.

 

Although this solution works, it includes two main caveats: additional cost for RBI and additional latency for the customer.

Rough cost analysis

In the lowest tier, Google charges 5 USD per 1000 requests. To make a rough estimation, PLK ES had a total of 214,995 “Manual Location Search” events in July 2024. This event is triggered when the customer selects an address from the dropdown in the store locator page. Now, assuming that all streets have a length of 10 characters (“Calle Mayor” length), we can estimate that the API will be called:

Estimated number of calls per month = 215,000 x 10 x 5 = 10,750,000

 

Multiplying by 5 is important since the geocoding will be called for each of the 5 Google’s predictions, even if they don’t appear on screen. This leads us to estimate an additional cost of 10,750 USD per month, for PLK ES. For a full estimation, we’d also have to include the remaining brands and markets.

Other potential problems

Another potential problem is that the Autocomplete Service returns at most 5 predictions, and this cannot be changed. This will probably impact users who live on a street with a common name, where the API might return 5 results outside of their city, and all would be filtered out. This will lead to the autocomplete showing now results found for a street that exists!

Related content

[Solution] Reduce delivery address errors - enhancements
[Solution] Reduce delivery address errors - enhancements
More like this
[Opportunity] Delivery address - inform customer that they are far away
[Opportunity] Delivery address - inform customer that they are far away
More like this
[Solution] MB WAY - new payment method
[Solution] MB WAY - new payment method
Read with this
[Solution] Reduce delivery address errors - core
[Solution] Reduce delivery address errors - core
More like this
[Solution] Delivery address - inform customer that they are far away
[Solution] Delivery address - inform customer that they are far away
Read with this
Analysis impact of changing autocomplete parameters
Analysis impact of changing autocomplete parameters
More like this