This is the Trace Id: a2e91bf69d6345d72f4f9d3c3dc79765
October 19, 2022

Delhaize Serbia digitizes its customers’ in-store shopping experience with an app based on Microsoft Azure

Operating through more than 480 stores across the country, Delhaize Serbia is the largest retail chain in Serbia and a member of the international retail chain Ahold Delhaize. As a market leader, the company is strategically committed to being an innovator that always brings customers a modern shopping experience. With an omnichannel approach to business and a desire to provide customers with innovative benefits that match their personal shopping habits, Delhaize Serbia decided to develop a loyalty application called "My Maxi", based on Microsoft Azure.

Delhaize Serbia

Putting customers first, the Delhaize Serbia retail chain continuously invests in modernization and innovation with the aim of providing clients with the highest quality procurement experience according to the latest standards. “We want to communicate with our customers better and provide exactly what they need,” says Dragoljub Jovković, IT Director at Delhaize Serbia. In order to achieve this, it was necessary to understand customers’ habits even better. For that, the company realized it needed a cloud-based digital solution, so the team approached their long-time partner Microsoft.

Together, the partners created a personalized loyalty application that raised the shopping experience to a digital level, bringing all users a variety of benefits and discounts in everyday purchases.

Maximizing the shopping experience

With Microsoft’s constant support throughout the entire project, Delhaize Serbia successfully developed My Maxi loyalty app—locally and from scratch—within six months. “Microsoft gave us a good proposal for the Azure platform and accommodated it to suit the processes and structures we would need. We also held weekly meetings with technical experts who would address our concerns and provide solutions or explanations,” says Jovković. “I would say our knowledge of cloud technology has grown thanks to this journey with the Microsoft team.”

Based on Microsoft Azure services, with Azure API Management and NET Core as a development tool, the company can now reach out to customers in a more effective and efficient way. “My Maxi app is an amazing solution that can optimize custom offers based on customers’ preferences, while key services do complex work in just a few milliseconds,” says Jovković.

“Before, we could only show a few hundred special offers prepared for our customers through different channels. But now, with “My Maxi”, they can view thousands of different promotions,” adds Nikola Zečević, Chief Digital Officer at Delhaize Serbia.

The loyalty app was first launched in just one city, Kragujevac, in Serbia but grew in national popularity quickly. “We gained 300,000 users within a few weeks after the national launch and, in a couple of months, half a million users started enjoying the benefits of “My Maxi” app—and that number continues to grow,” says Zečević. “Their satisfaction is evident since My Maxi is currently rated 4.8 out of 5 on one of the largest platforms for downloading applications.”

“The app is also inclusive, as not only the younger population uses it," Zečević says, “Initially, we were worried that our older customers wouldn’t be interested in the app. But now, we’re proud to say that 20 percent of our users are more than 55 years old.”

All the data collected from the app is transformed into useful insights through Power BI reporting. With these insights, Delhaize Serbia can now build even better relationships with its customers as well as offer other services that ease the shopping experience. Customers gain access to new shopping benefits with My Maxi app. “Our app users can now enjoy personalized promotions, additional discounts and numerous benefits with everyday purchases,” explains Zečević.

An innovative future

Having seen how the app has worked so well on a cloud platform, Delhaize Serbia plans to explore more cloud technology. “Next year, we will migrate the entire project to Azure DevOps to ensure even more impeccable operation of the My Maxi app,” says Žarko Jovanović, Team manager for local applications at Delhaize Serbia.

The company continues the digital transformation, which it believes will propel it forward into the future. “We believe it’s important to continuously improve our technical capabilities in order to be even more efficient in all areas of business. This is just the first step, and we’re glad to have Microsoft’s support on all levels,” concludes Jovković.

“Before we could only show a few hundred special offers prepared for our customers through different channels. But now, with “My Maxi”, they can view thousands of different promotions.”

Nikola Zečević, Chief Digital Officer, Delhaize Serbia

Take the next step

Fuel innovation with Microsoft

A man wearing headphones and smiling

Talk to an expert about custom solutions

Let us help you create customized solutions and achieve your unique business goals.
A woman smiling and a pointing to a screen showing some statistics

Drive results with proven solutions

Achieve more with the products and solutions that helped our customers reach their goals.

Follow Microsoft

`; }); html += `
`; return createElementFromHTML(html); } function createProductsHTML(productsEyebrow, products) { let html = `

${productsEyebrow}

`; return createElementFromHTML(html); } /** * Updates project details bar with metadata JSON. * @returns {void} */ async function updateProjectDetailsBar() { try { // Get all API project details bar nodes const apiProjectDetailBars = document.querySelectorAll(SELECTORS.PROJECT_DETAILS_BAR_API_DATA_NODE); // if there are no API project details bar nodes, return if (apiProjectDetailBars.length === 0) return; // Get the first and second project details bar const apiProjectDetailsBarParent = apiProjectDetailBars[0].parentNode.parentNode; const firstProjectDetailsBar = apiProjectDetailsBarParent.firstElementChild; const secondProjectDetailsBar = firstProjectDetailsBar.nextElementSibling; // Update the project details bars heading text const headingText = metadataJSON.headingText; const projectDetailsBarTitle = firstProjectDetailsBar.querySelector(SELECTORS.PROJECT_DETAILS_BAR_TITLE); if (headingText && projectDetailsBarTitle) { projectDetailsBarTitle.textContent = headingText; } // Update the project details bars content updateFirstProjectDetailsBar(firstProjectDetailsBar); updateSecondProjectDetailsBar(secondProjectDetailsBar); } catch (error) { console.error('Error updating Project Details Bar', error); } } /** * API Template Structure * * Project Details Bar 1 * Heading * Column 1 - Customer, Partner * Column 2 - Products * Column 3 - Services and Support * Footer - Divider **/ function updateFirstProjectDetailsBar(firstProjectDetailsBar) { const body = firstProjectDetailsBar.querySelector(SELECTORS.PROJECT_DETAILS_BAR_BODY); const columns = body.querySelectorAll(SELECTORS.COLUMNS); // clear the columns to be rebuilt columns.forEach(column => { column.innerHTML = ''; }); updateCustomers(columns[0]); updatePartner(columns[0]); updateProducts(columns[1]); updateServices(columns[2]); } function updateCustomers(firstColumn) { const { 'customer-name': customerName, 'customer-url': customerUrl, 'customer-eyebrow': customerEyebrow } = metadataJSON; if (!customerName || !customerUrl || !customerEyebrow) return; const customerSection = createSectionHTML(customerEyebrow, [{ text: customerName, url: customerUrl }]); firstColumn.appendChild(customerSection); } function updatePartner(firstColumn) { const { partners, 'partners-eyebrow': partnerEyebrow } = metadataJSON; if (!partners || partners.length === 0 || !partnerEyebrow) return; const partnerSection = createSectionHTML(partnerEyebrow, partners); firstColumn.appendChild(partnerSection); } function updateProducts(secondColumn) { const { products, 'products-eyebrow': productsEyebrow } = metadataJSON; if (!products || products.length === 0 || !productsEyebrow) return; const productsSection = createProductsHTML(productsEyebrow, products); secondColumn.appendChild(productsSection); } function updateServices(thirdColumn) { let { services, 'services-eyebrow': servicesEyebrow } = metadataJSON; if (!services || services.length === 0) return; servicesEyebrow = servicesEyebrow || 'SERVICES'; const servicesSection = createSectionHTML(servicesEyebrow, services); thirdColumn.appendChild(servicesSection); } /** * API Template Structure * * Project Details Bar 2 * No heading * Column 1 - Organization Size, Country * Column 2 - Business Need, Industry * Button * No footer */ function updateSecondProjectDetailsBar(secondProjectDetailsBar) { const body = secondProjectDetailsBar.querySelector(SELECTORS.PROJECT_DETAILS_BAR_BODY); const columns = body.querySelectorAll(SELECTORS.COLUMNS); // clear the first two columns columns[0].innerHTML = ''; columns[1].innerHTML = ''; updateOrganizationSize(columns[0]); updateCountry(columns[0]); updateBusinessNeed(columns[1]); updateIndustry(columns[1]); } function updateOrganizationSize(firstColumn) { const { 'organization-size': organizationSize, 'organizations-size-eyebrow': organizationsSizeEyebrow } = metadataJSON; if (!organizationSize || !organizationsSizeEyebrow) return; const organizationSizeSection = createSectionHTML(organizationsSizeEyebrow, [organizationSize]); firstColumn.appendChild(organizationSizeSection); } function updateCountry(firstColumn) { let { 'country-value': countryValue, 'country-eyebrow': countryEyebrow } = metadataJSON; if (!countryValue) return; countryEyebrow = countryEyebrow || 'COUNTRY'; const countrySection = createSectionHTML(countryEyebrow, [countryValue]); firstColumn.appendChild(countrySection); } function updateBusinessNeed(secondColumn) { const { 'business-need': businessNeed, 'business-need-eyebrow': businessNeedEyebrow } = metadataJSON; if (!businessNeed || businessNeed.length === 0 || !businessNeedEyebrow) return; const businessNeedSection = createSectionHTML(businessNeedEyebrow, businessNeed); secondColumn.appendChild(businessNeedSection); } function updateIndustry(secondColumn) { const { industries, 'industries-eyebrow': industriesEyebrow } = metadataJSON; if (!industries || industries.length === 0 || !industriesEyebrow) return; const industriesSection = createSectionHTML(industriesEyebrow, industries); secondColumn.appendChild(industriesSection); } /** * Set telemetry attributes on all anchor elements in the project details bar */ function setTelemetryAttributes() { const projectDetailsBars = document.querySelectorAll(SELECTORS.PROJECT_DETAILS_BAR); projectDetailsBars.forEach(projectDetailsBar => { // get component name and view name const componentName = projectDetailsBar.getAttribute(ATTRIBUTES.COMPONENT_NAME); const viewName = projectDetailsBar.querySelector(SELECTORS.PROJECT_DETAILS_BAR_VIEW)?.textContent; // get all project details bar list containers const projectDetailsBarListContainers = projectDetailsBar.querySelectorAll(SELECTORS.PROJECT_DETAILS_BAR_LIST_CONTAINER); projectDetailsBarListContainers.forEach(projectDetailListContainer => { // get container title const containerTitle = projectDetailListContainer.querySelector(SELECTORS.PROJECT_DETAILS_BAR_LIST_CONTAINER_TITLE)?.textContent.trim(); // get all project details bar lists const projectDetailsBarLists = projectDetailListContainer.querySelectorAll(SELECTORS.PROJECT_DETAILS_BAR_LIST); projectDetailsBarLists.forEach(projectDetailsBarList => { // get all project details bar list actions const projectDetailsBarListActions = projectDetailsBarList.querySelectorAll(SELECTORS.PROJECT_DETAILS_BAR_LIST_ACTIONS); projectDetailsBarListActions.forEach((projectDetailsBarListAction, i) => { let anchor = projectDetailsBarListAction.querySelector(SELECTORS.ACTION); if (anchor) { setAnchorTelemetryAttributes(anchor, viewName, containerTitle, componentName, i); } }); }); // get all related products const relatedProducts = projectDetailListContainer.querySelectorAll(SELECTORS.RELATED_PRODUCTS); relatedProducts.forEach(relatedProduct => { // get all related product actions const relatedProductActions = relatedProduct.querySelectorAll(SELECTORS.RELATED_PRODUCT); relatedProductActions.forEach((relatedProductAction, i) => { let anchor = relatedProductAction.querySelector(SELECTORS.ACTION); if (anchor) { setAnchorTelemetryAttributes(anchor, viewName, containerTitle, componentName, i); } }); }); }); }); } /** * Set anchor telemetry attributes * @param {HTMLElement} anchor - anchor element * @param {string} viewName - view name * @param {string} containerTitle - container title * @param {string} componentName - component name * @param {number} index - collection index */ function setAnchorTelemetryAttributes(anchor, viewName, containerTitle, componentName, index) { if (viewName) { anchor.setAttribute(ATTRIBUTES.DATA_BI_VIEW, viewName); } if (containerTitle) { anchor.setAttribute(ATTRIBUTES.DATA_BI_HN, containerTitle); } anchor.setAttribute(ATTRIBUTES.DATA_BI_COMPNM, componentName); anchor.setAttribute(ATTRIBUTES.DATA_BI_SN, index); anchor.setAttribute(ATTRIBUTES.DATA_BI_CT, dataBiCt); } // event listener for DOM ready document.addEventListener('DOMContentLoaded', () => { // Get the metadata JSON. If not found, wait for request manager to provide it. metadataJSON = window.ocReimagine?.CustomerStoryRequestManager?.storyMetadata; if (!metadataJSON) { document.addEventListener(EVENTS.METADATA, (e) => { metadataJSON = e.detail.storyMetadata; updateProjectDetailsBar(); }); } else { updateProjectDetailsBar(); } // Set telemetry attributes. setTelemetryAttributes(); }); })(document);