{"id":5843,"date":"2024-03-19T07:57:35","date_gmt":"2024-03-19T07:57:35","guid":{"rendered":"https:\/\/www.302.nl\/?page_id=5843"},"modified":"2024-03-19T07:58:09","modified_gmt":"2024-03-19T07:58:09","slug":"realtime-chat","status":"publish","type":"page","link":"https:\/\/www.302.nl\/en\/realtime-chat\/","title":{"rendered":"Realtime chat"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"5843\" class=\"elementor elementor-5843\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-9def061 elementor-section-height-min-height elementor-section-boxed elementor-section-height-default elementor-section-items-middle\" data-id=\"9def061\" data-element_type=\"section\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-558c3d0\" data-id=\"558c3d0\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-aaa7e2c elementor-widget elementor-widget-heading\" data-id=\"aaa7e2c\" data-element_type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;none&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\">Realtime chat\u200b<\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b544cc9 elementor-widget elementor-widget-heading\" data-id=\"b544cc9\" data-element_type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;none&quot;,&quot;_animation_delay&quot;:150}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h6 class=\"elementor-heading-title elementor-size-default\">Verschillen websockets versus reguliere requests<\/h6>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-deef464 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"deef464\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4bc17ea\" data-id=\"4bc17ea\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-ac7e227 elementor-widget elementor-widget-text-editor\" data-id=\"ac7e227\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Recentelijk hebben wij voor een klant een chat module afgeleverd. Deze module zorgt ervoor dat gebruikers vanuit verschillende rollen in realtime met elkaar kunnen communiceren. In onderstaand artikel leggen we uit hoe we hierin te werk zijn gegaan en welke technieken we daarvoor hebben gebruikt.\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b572b0a elementor-widget elementor-widget-heading\" data-id=\"b572b0a\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Realtime chat<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-613b98f elementor-widget elementor-widget-text-editor\" data-id=\"613b98f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Het portaal waarvoor deze module gemaakt is wordt gebouwd in het Laravel framework (php, backend) in combinatie met vue.js (javascript, frontend). Om te beginnen moest er eerst gekeken worden naar het realtime gedeelte. Je wilt namelijk dat de klant direct op het scherm een nieuw bericht ziet. Hiervoor wordt een techniek gebruikt die websockets heet. Normaal werkt een webpagina zo dat je data opvraagt uit de backend met een request. De frontend verzoekt dus data uit de backend. Maar voor een chat moet er ook data de andere kant op gestuurd kunnen worden. Hier komen de websockets in beeld. Met websockets wordt er een verbinding tot stand gebracht waarop data beide richtingen opgestuurd kan worden. Deze verbinding blijft actief waardoor de data dus realtime binnenkomt.\u00a0\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ca6ab23 elementor-widget elementor-widget-heading\" data-id=\"ca6ab23\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Verschillen websockets versus reguliere requests<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8e838a4 elementor-widget elementor-widget-text-editor\" data-id=\"8e838a4\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>In onderstaand schema laten we het verschil zien. Voor een normaal verzoek wordt er een \u201crequest\u201d en \u201cresponse\u201d systeem gebruikt. Waarbij elk verzoek een nieuwe connectie maakt. Bij websockets wordt er een \u201chandshake\u201d connectie gemaakt. Dit is een connectie die blijft bestaan. Vervolgens wordt er op deze verbinding geluisterd naar \u201cberichten\u201d. Deze \u201cberichten\u201d worden vanuit de backend via een \u201cbroadcast\u201d verzonden. Deze broadcast stuurt de berichten over een vooraf vastgesteld kanaal naar iedereen die op dit kanaal aan het luisteren is. Het luisteren gebeurt in de frontend (webpagina), in ons specifieke geval kan de backend alleen maar broadcasten en de frontend alleen maar luisteren.\u00a0\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4db1a61 elementor-widget elementor-widget-image\" data-id=\"4db1a61\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Websockets versus requests\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6MjYxMywidXJsIjoiaHR0cHM6XC9cL3d3dy4zMDIubmxcL3dwLWNvbnRlbnRcL3VwbG9hZHNcLzIwMjJcLzA0XC9pbWFnZS0xMy5wbmcifQ%3D%3D\">\n\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"417\" src=\"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1024x417.png\" class=\"attachment-large size-large wp-image-2613\" alt=\"Websockets versus requests\" srcset=\"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1024x417.png 1024w, https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-300x122.png 300w, https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-768x313.png 768w, https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1536x626.png 1536w, https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-245x100.png 245w, https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-196x80.png 196w, https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-394x161.png 394w, https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-915x373.png 915w, https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1240x505.png 1240w, https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1920x782.png 1920w, https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13.png 1966w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b79fc4e elementor-widget elementor-widget-heading\" data-id=\"b79fc4e\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Abonneren op kanalen<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f048221 elementor-widget elementor-widget-text-editor\" data-id=\"f048221\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Met de websockets kan de frontend zich dus \u201cabonneren\u201d op een kanaal en vervolgens kun je luisteren in dit kanaal naar specifieke berichten. We kunnen in die berichten waarnaar we luisteren ook data meesturen. Bijvoorbeeld een nieuw bericht. Maar hier komt een stukje beveiliging bij kijken. We willen niet dat gebruikers elkaars berichten kunnen ontvangen. We maken daarom voor iedere chat een nieuw kanaal aan. En we zorgen dat alleen gebruikers die verbonden zijn aan deze chat zich kunnen abonneren op dit kanaal. Hiermee verzekeren we dat gebruikers die niet bevoegd zijn ook niet kunnen meeluisteren.\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c8b3ff1 elementor-widget elementor-widget-heading\" data-id=\"c8b3ff1\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Beveiligen van data over websockets<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2249e83 elementor-widget elementor-widget-text-editor\" data-id=\"2249e83\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Omdat we voor iedere chat een nieuw kanaal aanmaken en we rekening willen houden met grote aantallen chats op 1 gebruiker moet er ook worden nagedacht over op welke kanalen we allemaal gaan luisteren. Wanneer we op heel veel kanalen tegelijk gaan luisteren kost dit veel rekenkracht en zal dit de snelheid van de applicatie in de weg zitten. Dus is er besloten om alleen te luisteren op het kanaal van een chat wanneer ook echt in dit gesprek bezig zijn als gebruiker. Er is dus altijd per scherm maximaal 1 chatkanaal waar actief naar geluisterd wordt. Maar dan zitten we met het volgende, hoe weet de gebruiker dat er in een andere chat een nieuw bericht binnen komt?\u00a0\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-25441b9 elementor-widget elementor-widget-heading\" data-id=\"25441b9\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Specifiek websocket kanaal voor gebruiker<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-42fbaa8 elementor-widget elementor-widget-text-editor\" data-id=\"42fbaa8\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Hiervoor hebben we een ander kanaal gemaakt waarnaar geluisterd wordt. Dit kanaal is specifiek voor een gebruiker. De gebruiker krijgt via dit kanaal alleen maar door dat er een ongelezen bericht is. Hier wordt geen data meegezonden met het bericht, alleen een getal dat aangeeft hoeveel ongelezen berichten er zijn. Doordat dit een algemeen kanaal is kan dit niet zo makkelijk afgeschermd worden. Alle gebruikers krijgen een eigen kanaal, maar omdat de websockets ook vanuit 1 gebruiker alle andere moet kunnen bereiken is het niet mogelijk dit kanaal helemaal dicht te zetten. Daarom worden hier expliciet niet de berichten zelf meegestuurd, maar krijgt de gebruiker wel een update dat er een nieuw bericht is. Zodra de betreffende chat dan wordt ge-opend worden de berichten pas opgehaald doormiddel van een request en wordt er geluisterd naar het kanaal van deze chat. Op deze manier zijn de berichten alleen beschikbaar voor de gebruiker die er toegang toe heeft en kunnen we toch aangeven dat er ongelezen berichten zijn.\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6899e21 elementor-widget elementor-widget-heading\" data-id=\"6899e21\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Chat beschikbaar voor diverse gebruikersrollen<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3437b43 elementor-widget elementor-widget-text-editor\" data-id=\"3437b43\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>In dit portaal zitten gebruikers met verschillende rollen. Zo zijn er flexwerkers, relaties (bedrijven die flexwerkers inhuren) en intercedenten (medewerkers van een uitzendbureau bijvoorbeeld). Per rol moest worden bepaald of deze gebruiker een chat mag starten. En zo ja welke gebruikers mag deze gebruiker uitnodigen voor een chat. Gelukkig waren er in deze portaal al afschermingen aanwezig waardoor dit een kwestie was van aanhaken aan een bestaand systeem.\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9a07d98 elementor-widget elementor-widget-heading\" data-id=\"9a07d98\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Chatgroepen met beheerder<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a6106a1 elementor-widget elementor-widget-text-editor\" data-id=\"a6106a1\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Net zoals je bij whatsapp bijvoorbeeld een beheerder hebt in een groep hebben we voor deze module ervoor gekozen dat er altijd minimaal 1 intercedent in de groep moet. De intercedent is dan meteen de beheerder van deze groep. Echter wilden we de intercedent niet de mogelijkheid geven om chats permanent te verwijderen voor een andere gebruiker. Bijvoorbeeld: een flexwerker stelt een vraag over een contract, de intercedent geeft antwoord. De flexwerker moet dit altijd terug kunnen vinden. Mocht de intercedent willen opschonen en deze chat verwijderen dan heeft de flexwerker geen toegang meer tot deze informatie. Chats worden daarom pas definitief verwijderd wanneer alle deelnemende gebruikers verwijderd zijn. Om de intercedent toch de optie te geven om op te schonen is er een archief functie bij gemaakt waarmee een intercedent een chat kan archiveren. De flexwerker kan deze nog steeds inzien, maar mag op dat moment geen nieuwe berichten meer plaatsen in deze chat.\u00a0\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1fc77e4 elementor-widget elementor-widget-heading\" data-id=\"1fc77e4\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Design &amp; UI<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c5058af elementor-widget elementor-widget-text-editor\" data-id=\"c5058af\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Volgende punt dat we moesten tackelen is het design. De functionaliteit is bekend, maar nu moet de klant er ook makkelijk mee kunnen werken. Hiervoor hebben we gekeken naar de werking van bestaande chat applicaties. We willen graag dat de gebruikers zonder na te denken meteen begrijpen hoe het werkt. Dit zorgde ervoor dat we het design van het portaal zoals het al aanwezig was wilde integreren met een stukje nieuwe layout. In het portaal hebben we veel \u201cdata\u201d schermen, dit zijn schermen waarop we veel data tegelijk tonen. Vaak moet de gebruiker hiervoor scrollen. Standaard starten we altijd bovenaan en kan de gebruiker naar beneden scrollen. Echter is bij een chat applicatie meestal standaard dat het laatste bericht onderaan staat. En dus wil je onderaan beginnen en de gebruiker de mogelijkheid geven om naar boven te scrollen. Ook hebben we ervoor gekozen om automatisch naar beneden te scrollen wanneer er een nieuw bericht binnen komt. De gebruiker wordt zo meteen geattendeerd op een nieuw bericht.\u00a0\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9e12028 elementor-widget elementor-widget-heading\" data-id=\"9e12028\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Testprocedure &amp; productie deploy<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-85238bb elementor-widget elementor-widget-text-editor\" data-id=\"85238bb\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Na het opleveren van een testomgeving is de QA afdeling van het bedrijf waarvoor het portaal wordt ontwikkeld aan de slag gegaan om te testen. Tijdens dit proces zijn er meerdere iteraties geweest. Tegelijkertijd is begonnen met het opzetten van de websockets op de productie omgeving. Omdat wij werken in docker containers was het logisch om voor de websockets een nieuwe container toe te voegen aan de reeds bestaande containers. Vervolgens moest de nieuwe container in het geheel mee gaan draaien en daarvoor was nog behoorlijk wat configuratie nodig. De websocket container is uiteindelijk een paar weken voor de release van deze feature al live gezet zodat we het gedrag van de container al in de gaten konden houden zonder dat hij al gebruikt werd door klanten. Dit gaf ons de mogelijkheid om dit proces goed te testen. Wanneer de websockets in gebruik worden genomen is het niet de bedoeling om deze container zomaar uit te zetten. Omdat de gebruikers met de frontend continu verbonden zijn willen we niet de container down halen. Ook hebben we goed getest of de verbindingen hersteld worden wanneer de container onverhoopt toch tijdelijk uitvalt.\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ed6623e elementor-widget elementor-widget-heading\" data-id=\"ed6623e\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Feature live &amp; feedback gebruikers<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d85bc36 elementor-widget elementor-widget-text-editor\" data-id=\"d85bc36\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Na de test periode van zowel de nieuwe container als de code kwam het groene licht dat de feature goedgekeurd was. De gebruikers waren erg blij met de nieuwe feature en we hebben vele positieve reacties gekregen vanuit de gebruikers. En natuurlijk zoals het hoort ook meteen wat nieuwe verzoeken omtrent extra functionaliteit, want een web portaal is nooit af. En dus blijven wij lekker verder ontwikkelen.\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>","protected":false},"excerpt":{"rendered":"<p>Realtime chat\u200b Verschillen websockets versus reguliere requests Recentelijk hebben wij voor een klant een chat module afgeleverd. Deze module zorgt ervoor dat gebruikers vanuit verschillende rollen in realtime met elkaar kunnen communiceren. In onderstaand artikel leggen we uit hoe we &hellip; <a href=\"https:\/\/www.302.nl\/en\/realtime-chat\/\">Read More<\/a><\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":25,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-5843","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Realtime chat - 302 SmartWork<\/title>\n<meta name=\"description\" content=\"Deze module zorgt ervoor dat gebruikers vanuit verschillende rollen in realtime met elkaar kunnen communiceren.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.302.nl\/en\/realtime-chat\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Realtime chat - 302 SmartWork\" \/>\n<meta property=\"og:description\" content=\"Deze module zorgt ervoor dat gebruikers vanuit verschillende rollen in realtime met elkaar kunnen communiceren.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.302.nl\/en\/realtime-chat\/\" \/>\n<meta property=\"og:site_name\" content=\"302 SmartWork\" \/>\n<meta property=\"article:modified_time\" content=\"2024-03-19T07:58:09+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1024x417.png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.302.nl\/realtime-chat\/\",\"url\":\"https:\/\/www.302.nl\/realtime-chat\/\",\"name\":\"Realtime chat - 302 SmartWork\",\"isPartOf\":{\"@id\":\"https:\/\/www.302.nl\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.302.nl\/realtime-chat\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.302.nl\/realtime-chat\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1024x417.png\",\"datePublished\":\"2024-03-19T07:57:35+00:00\",\"dateModified\":\"2024-03-19T07:58:09+00:00\",\"description\":\"Deze module zorgt ervoor dat gebruikers vanuit verschillende rollen in realtime met elkaar kunnen communiceren.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.302.nl\/realtime-chat\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.302.nl\/realtime-chat\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.302.nl\/realtime-chat\/#primaryimage\",\"url\":\"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1024x417.png\",\"contentUrl\":\"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1024x417.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.302.nl\/realtime-chat\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Thuis\",\"item\":\"https:\/\/www.302.nl\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Realtime chat\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.302.nl\/#website\",\"url\":\"https:\/\/www.302.nl\/\",\"name\":\"302 SmartWork\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.302.nl\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Realtime chat - 302 SmartWork","description":"Deze module zorgt ervoor dat gebruikers vanuit verschillende rollen in realtime met elkaar kunnen communiceren.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.302.nl\/en\/realtime-chat\/","og_locale":"en_US","og_type":"article","og_title":"Realtime chat - 302 SmartWork","og_description":"Deze module zorgt ervoor dat gebruikers vanuit verschillende rollen in realtime met elkaar kunnen communiceren.","og_url":"https:\/\/www.302.nl\/en\/realtime-chat\/","og_site_name":"302 SmartWork","article_modified_time":"2024-03-19T07:58:09+00:00","og_image":[{"url":"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1024x417.png","type":"","width":"","height":""}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.302.nl\/realtime-chat\/","url":"https:\/\/www.302.nl\/realtime-chat\/","name":"Realtime chat - 302 SmartWork","isPartOf":{"@id":"https:\/\/www.302.nl\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.302.nl\/realtime-chat\/#primaryimage"},"image":{"@id":"https:\/\/www.302.nl\/realtime-chat\/#primaryimage"},"thumbnailUrl":"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1024x417.png","datePublished":"2024-03-19T07:57:35+00:00","dateModified":"2024-03-19T07:58:09+00:00","description":"Deze module zorgt ervoor dat gebruikers vanuit verschillende rollen in realtime met elkaar kunnen communiceren.","breadcrumb":{"@id":"https:\/\/www.302.nl\/realtime-chat\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.302.nl\/realtime-chat\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.302.nl\/realtime-chat\/#primaryimage","url":"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1024x417.png","contentUrl":"https:\/\/www.302.nl\/wp-content\/uploads\/2022\/04\/image-13-1024x417.png"},{"@type":"BreadcrumbList","@id":"https:\/\/www.302.nl\/realtime-chat\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Thuis","item":"https:\/\/www.302.nl\/"},{"@type":"ListItem","position":2,"name":"Realtime chat"}]},{"@type":"WebSite","@id":"https:\/\/www.302.nl\/#website","url":"https:\/\/www.302.nl\/","name":"302 SmartWork","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.302.nl\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"}]}},"_links":{"self":[{"href":"https:\/\/www.302.nl\/en\/wp-json\/wp\/v2\/pages\/5843","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.302.nl\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.302.nl\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.302.nl\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.302.nl\/en\/wp-json\/wp\/v2\/comments?post=5843"}],"version-history":[{"count":4,"href":"https:\/\/www.302.nl\/en\/wp-json\/wp\/v2\/pages\/5843\/revisions"}],"predecessor-version":[{"id":5847,"href":"https:\/\/www.302.nl\/en\/wp-json\/wp\/v2\/pages\/5843\/revisions\/5847"}],"wp:attachment":[{"href":"https:\/\/www.302.nl\/en\/wp-json\/wp\/v2\/media?parent=5843"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}