3rd party integrations
...
Purple Analytics Readmode
Setup and Integration Guide
26 min
this guide provides step by step instructions for setting up and integrating purple analytics readmode into your purple publishing application table of contents /#prerequisites /#basic setup /#advanced configuration /#integration steps /#customization /#troubleshooting /#testing /#performance considerations /#best practices prerequisites before integrating purple analytics readmode, ensure you have purple analytics platform active purple analytics tracking implementation readmode ui components existing readmode interface elements swiper js for article navigation (if using multiple articles) modern browser support es6+ compatible environment required dependencies // required global objects window\ purple // purple platform interface window\ purple tracking // purple analytics tracking window\ purple metadata // purple metadata service window\ readmodeinited // promise that resolves when readmode ui is ready basic setup 1\ minimum configuration the simplest setup requires only initialization // create instance with default settings const purpleanalyticsreadmode = new purpleanalyticsreadmode(); // initialize when dom is ready function ondomready(callback) { if (document readystate === 'loading') { document addeventlistener('domcontentloaded', callback); } else { callback(); // dom is already ready } } ondomready(() => { purpleanalyticsreadmode init(); }); 2\ basic configuration add basic customization options const purpleanalyticsreadmode = new purpleanalyticsreadmode({ articlemergefields \['headline', 'kurzueberschrift'], articlemergeseparator ' | ' }); function ondomready(callback) { if (document readystate === 'loading') { document addeventlistener('domcontentloaded', callback); } else { callback(); // dom is already ready } } ondomready(() => { purpleanalyticsreadmode init(); }); 3\ with hooks add custom behavior using hooks const purpleanalyticsreadmode = new purpleanalyticsreadmode({ articlemergefields \['articlesection', 'headline'], articlemergeseparator ' ' }); // custom initialization logic purpleanalyticsreadmode oninitialized = function() { console log('readmode analytics is ready'); // add your custom initialization code here }; // custom page change logic purpleanalyticsreadmode onpagechanged = function(article, index) { console log(`switched to article ${article title} (page ${index})`); // add your custom page change code here }; function ondomready(callback) { if (document readystate === 'loading') { document addeventlistener('domcontentloaded', callback); } else { callback(); // dom is already ready } } ondomready(() => { purpleanalyticsreadmode init(); }); advanced configuration custom article field extraction configure which article fields to merge for analytics const purpleanalyticsreadmode = new purpleanalyticsreadmode({ // choose which fields to include in article full information articlemergefields \[ 'articlesection', // from article metadata 'rubrikentitel', // from dom p rubrikentitel 'headline', // from dom h1 headline 'kurzueberschrift' // from dom p kurzueberschrift 2z ], // how to separate the fields articlemergeseparator ' | ' }); integration steps step 1 error handling add comprehensive error handling const purpleanalyticsreadmode = new purpleanalyticsreadmode(); purpleanalyticsreadmode oninitialized = function() { console log('✅ readmode analytics initialized successfully'); }; ondomready(async () => { try { await purpleanalyticsreadmode init(); console log('✅ readmode initialization completed'); } catch (error) { console error('❌ failed to initialize readmode analytics ', error); // optional report error to your error tracking service if (window\ errortracker) { window\ errortracker report('readmode init failed', error); } } }); // handle cleanup on page unload window\ addeventlistener('beforeunload', () => { try { purpleanalyticsreadmode destroy(); } catch (error) { console warn('error during readmode cleanup ', error); } }); customization custom event handling add custom functionality using the hooks system const purpleanalyticsreadmode = new purpleanalyticsreadmode(); // use the onpagechanged hook for custom page change behavior purpleanalyticsreadmode onpagechanged = function(article, index) { updatecustomui(article); notifyothersystems(article); }; function updatecustomui(article) { // update your custom ui elements const customtitle = document queryselector('#custom article title'); if (customtitle) { customtitle textcontent = article title; } } function notifyothersystems(article) { // notify other parts of your application window\ dispatchevent(new customevent('readmode\ articlechanged', { detail { article } })); } custom timetracker usage use the timetracker class independently // create a custom timer for different purposes const customtimer = new timetracker(); // track time for custom interactions document addeventlistener('scroll', () => { if (!customtimer starttime) { customtimer start(); } }); document addeventlistener('click', () => { if (customtimer starttime && !customtimer stoptime) { customtimer stop(); const scrolltime = customtimer getelapsedtime(); console log(`user scrolled for ${scrolltime}ms`); // track custom metric window\ purple tracking trackaction('custom scroll time', { time spent ms scrolltime, time spent formatted customtimer getformattedelapsedtime() }); } }); platform specific configuration adapt configuration based on platform // detect platform const platform = window\ purple? metadata? getmetadata? ('platform') || 'unknown'; let config = { articlemergefields \['headline'], articlemergeseparator ' ' }; // platform specific configurations switch (platform) { case 'ios' config articlemergefields = \['articlesection', 'headline']; config articlemergeseparator = ' | '; break; case 'android' config articlemergefields = \['headline', 'kurzueberschrift']; config articlemergeseparator = ' '; break; case 'web' config articlemergefields = \['articlesection', 'rubrikentitel', 'headline', 'kurzueberschrift']; config articlemergeseparator = ' | '; break; } const purpleanalyticsreadmode = new purpleanalyticsreadmode(config); troubleshooting common issues 1\ purple interface not available problem purple tracking trackaction is not a function solution // add timeout for purple interface resolution const purpleanalyticsreadmode = new purpleanalyticsreadmode(); async function initwithretry(maxretries = 10) { for (let i = 0; i < maxretries; i++) { try { if (window\ purple && window\ purple tracking) { await purpleanalyticsreadmode init(); return; } } catch (error) { console warn(`init attempt ${i + 1} failed `, error); } await new promise(resolve => settimeout(resolve, 500)); } throw new error('failed to initialize after maximum retries'); } ondomready(() => { initwithretry() catch(error => { console error('failed to initialize readmode ', error); }); }); 2\ memory leaks problem event listeners not properly cleaned up solution // ensure proper cleanup let readmodeinstance = null; function initreadmode() { if (readmodeinstance) { readmodeinstance destroy(); } readmodeinstance = new purpleanalyticsreadmode(); return readmodeinstance init(); } // clean up on navigation or page unload window\ addeventlistener('beforeunload', () => { if (readmodeinstance) { readmodeinstance destroy(); readmodeinstance = null; } }); // for spa applications, clean up on route change window\ addeventlistener('popstate', () => { if (readmodeinstance) { readmodeinstance destroy(); readmodeinstance = null; } }); testing unit testing test the timetracker class // example test cases function testtimetracker() { const tracker = new timetracker(); // test normal flow tracker start(); settimeout(() => { tracker stop(); const elapsed = tracker getelapsedtime(); console assert(elapsed >= 100, 'should track at least 100ms'); const formatted = tracker getformattedelapsedtime(); console assert(formatted includes('min'), 'should include "min" in formatted time'); }, 100); // test error cases const emptytracker = new timetracker(); try { emptytracker getelapsedtime(); console assert(false, 'should throw error when not started'); } catch (e) { console assert(true, 'correctly throws error'); } } integration testing test the full integration function testreadmodeintegration() { const testinstance = new purpleanalyticsreadmode({ articlemergefields \['headline'], articlemergeseparator ' | ' }); let initcalled = false; let pagechangecalled = false; testinstance oninitialized = function() { initcalled = true; console log('✅ initialization hook called'); }; testinstance onpagechanged = function(article, index) { pagechangecalled = true; console log('✅ page change hook called'); }; return testinstance init() then(() => { console assert(initcalled, 'oninitialized should be called'); // simulate page change return testinstance handlepagechange(\[ { id 'test 1', title 'test article', section 'test' } ], 0); }) then(() => { console assert(pagechangecalled, 'onpagechanged should be called'); console log('✅ integration test passed'); // clean up testinstance destroy(); }); } performance considerations lazy loading only initialize when needed // only initialize when readmode is actually opened let readmodeinstance = null; window\ openreadmode = function() { if (!readmodeinstance) { readmodeinstance = new purpleanalyticsreadmode(); readmodeinstance init(); } }; memory management monitor memory usage // periodic memory usage reporting setinterval(() => { if (window\ performance && window\ performance memory) { const memory = window\ performance memory; console log('memory usage ', { used math round(memory usedjsheapsize / 1024 / 1024) + 'mb', total math round(memory totaljsheapsize / 1024 / 1024) + 'mb' }); } }, 30000); // every 30 seconds best practices 1\ always use error handling try { await purpleanalyticsreadmode init(); } catch (error) { console error('readmode initialization failed ', error); // graceful fallback } 2\ clean up resources // always destroy instances when done window\ addeventlistener('beforeunload', () => { if (purpleanalyticsreadmode) { purpleanalyticsreadmode destroy(); } }); 3\ use appropriate configuration // configure based on your actual content structure const purpleanalyticsreadmode = new purpleanalyticsreadmode({ // only include fields that exist in your content articlemergefields \['headline', 'kurzueberschrift'], // use separators that make sense for your data articlemergeseparator ' | ' }); 4\ monitor performance // track initialization time const initstart = performance now(); purpleanalyticsreadmode init() then(() => { const inittime = performance now() initstart; console log(`readmode initialized in ${inittime tofixed(2)}ms`); }); 5\ validate configuration function validateconfig(config) { if (config articlemergefields && !array isarray(config articlemergefields)) { throw new error('articlemergefields must be an array'); } if (config articlemergeseparator && typeof config articlemergeseparator !== 'string') { throw new error('articlemergeseparator must be a string'); } return true; } const config = { articlemergefields \['headline'], articlemergeseparator ' | ' }; if (validateconfig(config)) { const purpleanalyticsreadmode = new purpleanalyticsreadmode(config); } this guide should provide you with everything needed to successfully integrate purple analytics readmode into your application for additional support or questions, refer to the main readmode md documentation