Co (ne)umí umělá inteligence v zákaznické péči? Vše, co potřebujete vědět

27. 5. 2025
Doba čtení: 8 minut

Sdílet

Žena znechucená při volání na zákaznickou linku s umělou inteligencí
Autor: Shutterstock
Ilustrační obrázek
Také zákaznický servis spadá mezi obory, kde je možné využít umělou inteligenci. Jaké to má výhody? A jsou zde i nějaká úskalí a rizika?

minulém článku zaměřeném na zákaznický servis a umělou inteligenci jsme se zaměřovali na to, kdy se rozhodnout pro člověka a kdy využít AI a co je při tom důležité. Nyní přinášíme přehled výhod a také nevýhod.

Co se dozvíte v článku
  1. Hlavní je rychlost a dostupnost
  2. Jaké jsou další výhody?
  3. Hlavní rizika a výzvy
  4. Pořád jde jen o technologii
  5. Nebojte se začít

Hlavní je rychlost a dostupnost

Jak na úvod vyjmenovává Tomáš Malovec, CEO & Founder společnosti Born Digital, technologie přinášejí rychlost, dostupnost a přesnost, tedy tři klíčové hodnoty moderního zákaznického servisu. Pomáhají filtrovat dotazy, automatizovat odpovědi a vytvářet přehledná data pro další zlepšování služeb. Díky nim můžete obsloužit více zákazníků najednou, snížit náklady, a přitom zvyšovat úroveň služeb. A co je možná nejcennější – umožňují personalizovat péči tak, aby se zákazník necítil jako číslo, ale jako skutečně důležitý klient, doplňuje.

Odborníci se shodují, že hlavní výhodou použití AI technologií v zákaznickém servisu je rychlost a dostupnost. Jak popisuje Tomáš Vacek, podnikatel a partner reklamní a marketingové agentury Contexto, AI umožňuje okamžitě odpovídat na velké množství dotazů, zajistit servis 24 hodin denně a významně zvýšit efektivitu provozu. Technologie rovněž dokážou sbírat a analyzovat data, díky čemuž mohou firmy lépe pochopit své zákazníky, zlepšovat své produkty a služby a celkově posilovat vztahy se zákazníky, dodává.

Podle Mária Roženského, zakladatele & CEO SupportBoxu, je hlavní výhoda zcela zřejmá, a to je časová úspora, kdy chatboti dokáží pracovat 24/7 a neustále se zlepšovat podle toho, jak jim dáváme další a další schopnosti. Díky tomu, že dokáží odpovědět zákazníkovi i v jednu hodinu ráno, nepřicházíme o objednávky. Stejně tak jejich schopnost zpracovat obrovské množství zpráv za krátký okamžik nám dává nepřeberné možnosti škálování v oblastech, kde to dosud bylo náročné. Například v oblasti kontroly kvality odpovědí, kdy běžný manažer zkontroluje maximálně desítky ticketů za den, kdežto to AI jich hravě zvládne tisíce, a to bez emocí, či osobní preference, dodává a doplňuje, že nesmíme zapomenout také na multijazyčnost, kdy AI natrénujete v jednom jazyce, ale ona následně dokáže odpovědět v libovolném jazyce.

Vladimir Šandera, spoluzakladatel společnosti Smartsupp, k pokrytí zákaznické péče 24 hodin denně, 7 dní v týdnu uvádí, že podle dat Smartsupp až dvě třetiny zákazníků nakupují mimo běžnou pracovní dobu, ale očekávají odpověď ihned, takže když ji nedostanou, nemají důvod na e-shopu dál zůstávat. Většina e-shopů – s výjimkou těch úplně největších – však nabízí zákaznickou podporu jen 8 hodin denně, čímž přichází o zákazníky, podotýká.

Jaké jsou další výhody?

Radek Šlang, IT ředitel Konecty pro Střední Evropu, zmiňuje, že technologie zvyšují dostupnost, zrychlují reakce a odlehčují agentům od rutiny. AI pomáhá s dohledáváním informací, zpracováním požadavků, přepisem hovorů i shrnutím konverzací, takže se agent může plně soustředit na zákazníka. Pro management je podle něj zásadní autonomní analytika. AI automaticky hodnotí interakce podle předem dané matice, detekuje přerušování, nevyřešené požadavky, sleduje tón hlasu a generuje personalizované tipy pro zlepšení výkonu, vysvětluje a přidává, že skvělé jsou i platformy, které samy vyhodnocují provozní a kvalitativní KPI bez exportů a ručních reportů.

Vojtěch Dlouhý, CEO Feedyou, říká, že hlavní výhody použití umělé inteligence zahrnují: dostupnost 24/7, rychlost a efektivitu, personalizaci, snížení nákladů, a konzistenci, kdy AI zajišťuje jednotnou kvalitu odpovědí napříč různými kanály komunikace. Lukáš Sedláček, historik, publicista a zakladatel Týdne inovací, k tomu doplňuje ještě škálovatelnost, tedy že jeden chatbot může obsloužit stovky zákazníků zároveň a výše zmíněnou analytiku, kdy technologie dokážou sbírat data o tom, co zákazníci řeší nejčastěji, a tím napomáhat zlepšení služeb i produktů. Samozřejmostí je pak také úspora nákladů v podobě snížení počtu rutinních dotazů, které by jinak musel řešit člověk.

To, že automatizace snižuje vytížení celého týmu, takže se operátoři mohou věnovat jen těm nejsložitějším dotazům nebo leadům s největším potenciálem zdůrazňuje také Vladimir Šandera. Podle jejich nejnovější studie, ve které čerpali z dat 175 000 klientů Smartsupp z celého světa za rok 2024, e-shopy které kombinují live chat a chatbota odbaví 6× víc dotazů oproti těm, které využívají pouze live chat. E-shopy s chatbotem navíc dokázaly průměrně odpovědět na 89,2 % dotazů, kdežto e-shopy, které používaly výhradně live chat jen 71,2 % dotazů, upřesňuje.

Michal Bočan, zakladatel aplikace Podpisovna, podotýká, že možnosti sběru a hodnocení dat technologií jsou nesrovnatelně větší než u běžného člověka. Z tohoto pohledu mohou zákazníkovi poskytnout mnohem širší spektrum informací v mnohem kratší době, uvádí. Náš AI agent umí v reálném čase navrhovat odpovědi, a to v různých jazycích, automaticky kategorizovat tickety nebo shrnout předchozí komunikaci. To výrazně šetří čas operátorům a zrychluje reakci zákazníkovi, popisuje Jiří Havlíček, CEO společnosti Daktela a dodává, že díky chytrému směrování dokážou spojit klienta s tím nejlepším operátorem na daný typ problému. A celkově se zvyšuje konzistence i kvalita odpovědí, což se odráží ve vyšší spokojenosti zákazníků, shrnuje.

Chatbot nebo člověk? Zákaznický servis hledá rovnováhu v éře umělé inteligence Přečtěte si také:

Chatbot nebo člověk? Zákaznický servis hledá rovnováhu v éře umělé inteligence

Hlavní rizika a výzvy

Podle Tomáše Malovce je jedním z hlavních rizik přílišná automatizace na úkor lidského přístupu: zákazník může mít pocit, že mluví se zdí, pokud mu AI nerozumí nebo stále opakuje to samé. Toto je přistup většiny současných chatbotů postavených na starších technologiích a je to také důvod proč lidi nemají rádi chatboty, zmiňuje a dodává, že chatbota postaveného na nejnovějších technologiích ale už nerozeznáte od člověka, a navíc dělá méně chyb než lidé, nemá své nálady a je s vámi trpělivý a slušný za každé situace. Mimochodem to je hlavní aspekt, jak dokážete rozeznat rozdíl, podotýká.

Také Radek Šlang vidí jako hlavní riziko neosobní a frustrující zážitek, pokud systém nepochopí dotaz nebo znemožní přechod k živému agentovi. Proto je podle něj důležité průběžné ladění na základě reálné zpětné vazby. Dále je klíčová ochrana dat. AI často pracuje s osobními údaji, takže je nutné mít dobře nastavené procesy a transparentní komunikaci. A samozřejmě, technologie musí odpovídat provozu. Jinak spíš přidělávají práci, popisuje.

Mezi hlavní rizika podle Lukáše Sedláčka patří:

  •  Frustrace zákazníků, pokud je chatbot příliš „robotický“, nerozumí nebo nedokáže předat konverzaci člověku.
  • Přílišná automatizace – snaha řešit úplně vše pomocí AI může působit neosobně a poškodit značku.
  • Chybovost AI – špatně natrénovaný model může dávat nevhodné nebo nepřesné odpovědi.
  • Ochrana dat a soukromí – při práci s osobními údaji musí být vše v souladu s GDPR a dalšími předpisy.
  • Složitá integrace – napojení AI na interní systémy může být náročné a časově i finančně nákladné.

Vojtěch Dlouhý k výzvám řadí kromě omezeného porozumění složitým dotazům nebo bezpečnosti a ochraně osobních údajů také například závislost na kvalitě dat (výkon AI je přímo úměrný kvalitě a množství dostupných dat pro trénink) nebo nedostatek empatie. V situacích vyžadujících lidský přístup může AI působit neosobně. Proto voicebot pro personalizovaný upsell či cross-sell ano, lead generation ve smyslu navolávání lidí a uzavírání obchodů ne, doporučuje.

Pořád jde jen o technologii

Podle Michala Bočana jsou úskalí otázkou „lidské“ komunikace. Vysvětluje, že technologie se zdokonalují velmi rychle, ale stále nedokáží rozeznat lidské emoce jinak než pomocí hodnocení slov a slovních obratů. Pokud tedy uživatel používá při komunikaci s AI jemnější emoce, dochází někdy k paradoxním situacím a komunikace se stává nevalidní. Proto je dobré mít se na pozoru v jaké oblasti a jakých situacích chatboty a AI obecně využít, připomíná.

Také Mário Roženský zdůrazňuje, že se jedná stále pouze o technologii, a přestože nám přijde inteligentní, tak je to pouze generátor slov. A i přes všechnu snahu ji usměrňovat, stále má tato technologie tendence k určitému vymýšlení si. Proto je potřeba neustálá kontrola odpovědí, doplňování informací do znalostní báze a vylepšování pravidel. Přesto se v řadě firem setkáváme s tím, že AI zapnou a více ji již nekontrolují, doplňuje.

Podle Jiřího Havlíčka právě špatné nasazení bez strategie a bez dat bývá největší chybou. Chatbot, který nerozumí a nedokáže pomoct, vašeho zákazníka jen frustruje. AI bez kontroly může generovat nevhodné odpovědi. A přehnaná automatizace bez možnosti kontaktovat člověka zákazníka odradí, vyjmenovává s tím, že klíčové je testování, průběžné učení a možnost okamžitého přepnutí na člověka. A hlavně: technologie by měly být pomocníkem, ne překážkou – jak pro zákazníka, tak pro tým zákaznické péče, dodává.

Ve Smartsupp rozhodně nedoporučují rozpustit celý tým zákaznické podpory a spoléhat se, že umělá inteligence udělá veškerou práci za vás. Radí AI vnímat spíš jako příležitost k dalšímu růstu a lepší efektivitě než jako nástroj, který nahradí vaše stávající zaměstnance. Pamatujte také na to, že AI je jen tak dobrá, jak kvalitní má zdroje a materiály. Vaše firma by proto měla mít dobře zdokumentované procesy a informace o produktech, shrnuje.

Nebojte se začít

Jiří Havlíček radí začít jednoduše. Vyberte si tři nejčastější otázky, které denně řešíte, a automatizujte je. Sledujte zpětnou vazbu, vyhodnocujte efektivitu a postupně přidávejte další scénáře. Vnímejte AI ne jako náhradu lidí, ale jako kolegu do týmu – „parťáka“, který pomáhá s rutinními úkoly, upřesňuje.

K tomu, začít jednoduše a vybrat konkrétní proces, kde AI přinese rychlý efekt, nabádá také Radek Šlang. Testujte, vylepšujte a postupně rozšiřujte. A nezapomeňte: AI je nástroj, ne cíl. Největší hodnotu pořád přináší člověk – jeho přístup a empatie, doplňuje s tím, že z pohledu BPO společnosti jako Konecta vidí velký potenciál v prediktivních funkcích. AI může pomoci s plánováním směn, predikcí provozu, automatickým směrováním hovorů a tiketů, nebo optimalizací vytížení týmů, konkretizuje.

Marketing meeting Influenceři a sociální sítě

Vojtěch Dlouhý doporučuje firmám:

  • Začít s pilotním projektem: Otestujte AI na konkrétním procesu nebo oddělení, abyste mohli vyhodnotit její přínosy.
  • Zajistit integraci s existujícími systémy: Pro maximální efektivitu by měla AI spolupracovat s vašimi CRM a dalšími nástroji.
  • • Pravidelně školit a aktualizovat AI: Udržujte AI systémy aktuální a přizpůsobujte je měnícím se potřebám zákazníků.
  • Získávat zpětnou vazbu od zákazníků: Sledujte, jak zákazníci reagují na interakce s AI, a na základě toho provádějte úpravy.
  • Zachovat lidský kontakt tam, kde je to důležité: AI by měla doplňovat, nikoli nahrazovat lidský přístup v klíčových momentech zákaznické cesty.

Nebojte se využívat umělou inteligenci: není to nic složitého a určitě k tomu nebudete potřebovat tým IT specialistů, vyzývá Vladimir Šandera s tím, že AI je stále poměrně mladá technologie, takže ji doporučují vnímat hlavně jako příležitost udělat si pořádek ve vlastních procesech, zdrojích dat a zvýšit svůj tržní podíl. Umělá inteligence tu s námi pravděpodobně zůstane a čím dříve do rozjíždějícího vlaku naskočíte, tím méně vás bude rozjezd bolet, uzavírá.

Autor článku

Jana Langerová píše o marketingu, podnikatelských příbězích a digitálních trendech.​ Profil autorky →

'; document.getElementById('preroll-iframe').onload = function () { setupIframe(); } prerollContainer = document.getElementsByClassName('preroll-container-iframe')[0]; } function setupIframe() { prerollDocument = document.getElementById('preroll-iframe').contentWindow.document; let el = prerollDocument.createElement('style'); prerollDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:20px;right:25px}"; videoContent = prerollDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('PREROLL sound allowed'); // setUpIMA(true); videoContent.volume = 1; videoContent.muted = false; setUpIMA(); }).catch(function () { console.log('PREROLL sound forbidden'); videoContent.volume = 0; videoContent.muted = true; setUpIMA(); }); } } function setupDimensions() { prerollWidth = Math.min(iinfoPrerollPosition.offsetWidth, 480); prerollHeight = Math.min(iinfoPrerollPosition.offsetHeight, 320); } function setUpIMA() { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Preroll advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = prerollWidth; // adsRequest.linearAdSlotHeight = prerollHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. prerollDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( prerollDocument.getElementById('adContainer'), videoContent); } function unmutePrerollAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } } function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(prerollWidth, prerollHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } function onAdEvent(adEvent) { const ad = adEvent.getAd(); console.log('Preroll event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: if (!ad.isLinear()) { videoContent.play(); } prerollDocument.getElementById('adContainer').style.width = '100%'; prerollDocument.getElementById('adContainer').style.maxWidth = '640px'; prerollDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); if (ad.isLinear()) { intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } prerollDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (prerollLastError === 303) { playYtVideo(); } break; case google.ima.AdEvent.Type.COMPLETE: if (ad.isLinear()) { clearInterval(intervalTimer); } playYtVideo(); break; } } function onAdError(adErrorEvent) { console.log(adErrorEvent.getError()); prerollLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { playYtVideo(); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoPrerollPosition.remove(); playPrerollAd(); } else { return false; } adVolume = 1; return true; } function onContentPauseRequested() { videoContent.pause(); } function onContentResumeRequested() { videoContent.play(); } function onActiveView() { if (prerollContainer) { const containerOffset = prerollContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (prerollPaused) { adsManager.resume(); prerollPaused = false; } return true; } else { if (!prerollPaused) { adsManager.pause(); prerollPaused = true; } } } return false; } function playYtVideo() { iinfoPrerollPosition.remove(); youtubeIframe.style.display = 'block'; youtubeIframe.src += '&autoplay=1&mute=1'; } }
Upozorníme vás na články, které by vám neměly uniknout (maximálně 2x týdně).
'; document.getElementById('outstream-iframe').onload = function () { setupIframe(); } replayScreen = document.getElementById('iinfoOutstreamReplay'); iinfoOutstreamPosition = document.getElementById('iinfoOutstreamPosition'); outstreamContainer = document.getElementsByClassName('outstream-container')[0]; setupReplayScreen(); } function setupIframe() { outstreamDocument = document.getElementById('outstream-iframe').contentWindow.document; let el = outstreamDocument.createElement('style'); outstreamDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:-5px;right:25px}"; videoContent = outstreamDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; if ( location.href.indexOf('rejstriky.finance.cz') !== -1 || location.href.indexOf('finance-rejstrik') !== -1 || location.href.indexOf('firmy.euro.cz') !== -1 || location.href.indexOf('euro-rejstrik') !== -1 || location.href.indexOf('/rejstrik/') !== -1 || location.href.indexOf('/rejstrik-firem/') !== -1) { outstreamDirectPlayed = true; soundAllowed = true; iinfoVastUrlIndex = 0; } if (!outstreamDirectPlayed) { console.log('OUTSTREAM direct'); setUpIMA(true); } else { if (soundAllowed) { const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('OUTSTREAM sound allowed'); setUpIMA(false); }).catch(function () { console.log('OUTSTREAM sound forbidden'); renderBanner(); }); } } else { renderBanner(); } } } function getWrapper() { let articleWrapper = document.querySelector('.rs-outstream-placeholder'); // Outstream Placeholder from RedSys manipulation if (articleWrapper && articleWrapper.style.display !== 'block') { articleWrapper.innerHTML = ""; articleWrapper.style.display = 'block'; } // Don't render OutStream on homepages if (articleWrapper === null) { if (document.querySelector('body.p-index')) { return null; } } if (articleWrapper === null) { articleWrapper = document.getElementById('iinfo-outstream'); } if (articleWrapper === null) { articleWrapper = document.querySelector('.layout-main__content .detail__article p:nth-of-type(6)'); } if (articleWrapper === null) { // Euro, Autobible, Zdravi articleWrapper = document.querySelector('.o-article .o-article__text p:nth-of-type(6)'); } if (articleWrapper === null) { articleWrapper = document.getElementById('sidebar'); } if (!articleWrapper) { console.error("Outstream wrapper of article was not found."); } return articleWrapper; } function setupDimensions() { outstreamWidth = Math.min(iinfoOutstreamPosition.offsetWidth, 480); outstreamHeight = Math.min(iinfoOutstreamPosition.offsetHeight, 320); } /** * Sets up IMA ad display container, ads loader, and makes an ad request. */ function setUpIMA(direct) { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); if (direct) { adsRequest.adTagUrl = directVast; console.log('Outstream DIRECT CAMPAING advert: ' + directVast); videoContent.muted = true; videoContent.volume = 0; outstreamDirectPlayed = true; } else { adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Outstream advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; } // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = outstreamWidth; // adsRequest.linearAdSlotHeight = outstreamHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function setupReplayScreen() { replayScreen.addEventListener('click', function () { iinfoOutstreamPosition.remove(); iinfoVastUrlIndex = 0; outstreamInit(); }); } /** * Sets the 'adContainer' div as the IMA ad display container. */ function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. outstreamDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( outstreamDocument.getElementById('adContainer'), videoContent); } function unmuteAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } } /** * Loads the video content and initializes IMA ad playback. */ function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(outstreamWidth, outstreamHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } /** * Handles the ad manager loading and sets ad event listeners. * @param { !google.ima.AdsManagerLoadedEvent } adsManagerLoadedEvent */ function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } /** * Handles actions taken in response to ad events. * @param { !google.ima.AdEvent } adEvent */ function onAdEvent(adEvent) { // Retrieve the ad from the event. Some events (for example, // ALL_ADS_COMPLETED) don't have ad object associated. const ad = adEvent.getAd(); console.log('Outstream event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: // This is the first event sent for an ad - it is possible to // determine whether the ad is a video ad or an overlay. if (!ad.isLinear()) { // Position AdDisplayContainer correctly for overlay. // Use ad.width and ad.height. videoContent.play(); } outstreamDocument.getElementById('adContainer').style.width = '100%'; outstreamDocument.getElementById('adContainer').style.maxWidth = '640px'; outstreamDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); // This event indicates the ad has started - the video player // can adjust the UI, for example display a pause button and // remaining time. if (ad.isLinear()) { // For a linear ad, a timer can be started to poll for // the remaining time. intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } outstreamDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (outstreamLastError === 303) { if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } } break; case google.ima.AdEvent.Type.COMPLETE: // This event indicates the ad has finished - the video player // can perform appropriate UI actions, such as removing the timer for // remaining time detection. if (ad.isLinear()) { clearInterval(intervalTimer); } if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } break; } } /** * Handles ad errors. * @param { !google.ima.AdErrorEvent } adErrorEvent */ function onAdError(adErrorEvent) { // Handle the error logging. console.log(adErrorEvent.getError()); outstreamLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { renderBanner(); } } function renderBanner() { if (isBanner) { console.log('Outstream: Render Banner'); iinfoOutstreamPosition.innerHTML = ""; iinfoOutstreamPosition.style.height = "330px"; iinfoOutstreamPosition.appendChild(bannerDiv); } else { console.log('Outstream: Banner is not set'); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoOutstreamPosition.remove(); outstreamInit(); } else { return false; } adVolume = 1; return true; } /** * Pauses video content and sets up ad UI. */ function onContentPauseRequested() { videoContent.pause(); // This function is where you should setup UI for showing ads (for example, // display ad timer countdown, disable seeking and more.) // setupUIForAds(); } /** * Resumes video content and removes ad UI. */ function onContentResumeRequested() { videoContent.play(); // This function is where you should ensure that your UI is ready // to play content. It is the responsibility of the Publisher to // implement this function when necessary. // setupUIForContent(); } function onActiveView() { if (outstreamContainer) { const containerOffset = outstreamContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (outstreamPaused) { adsManager.resume(); outstreamPaused = false; } return true; } else { if (!outstreamPaused) { adsManager.pause(); outstreamPaused = true; } } } return false; } let outstreamInitInterval; if (typeof cpexPackage !== "undefined") { outstreamInitInterval = setInterval(tryToInitializeOutstream, 100); } else { const wrapper = getWrapper(); if (wrapper) { let outstreamInitialized = false; window.addEventListener('scroll', () => { if (!outstreamInitialized) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { outstreamInit(); outstreamInitialized = true; } } }); } } function tryToInitializeOutstream() { const wrapper = getWrapper(); if (wrapper) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { if (cpexPackage.adserver.displayed) { clearInterval(outstreamInitInterval); outstreamInit(); } } } else { clearInterval(outstreamInitInterval); } } }
OSZAR »