{"id":18223,"date":"2018-04-03T11:30:06","date_gmt":"2018-04-03T11:30:06","guid":{"rendered":"https:\/\/www.heartinternet.uk\/blog\/?p=18223"},"modified":"2018-04-03T11:30:06","modified_gmt":"2018-04-03T11:30:06","slug":"5-things-you-didnt-know-a-browser-could-do","status":"publish","type":"post","link":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/","title":{"rendered":"5 things you didn&#8217;t know a browser could do!"},"content":{"rendered":"<p>We tend to see the web as a simple thing. A place to get some information, send an email, or publish a detailed report of our day on social media to get some virtual likes. When we want to do a little bit more, we usually turn to desktop software or mobile apps.<\/p>\n<p>Modern web browsers, however, have evolved from the simple pieces of software they were when the web was born to advanced programs crammed with useful APIs. In this article I will explain five things that are possible in (some) modern browsers and illustrate each API with some code examples and a little demonstration.<\/p>\n<p>It\u2019s worth knowing that some of these APIs don&#8217;t work in all modern browsers, and should never be the core of your website or web app, but a nice addition. Look at them as the cherry on the top of an already delicious pie.<\/p>\n<p>Sit back, relax and learn why the web is so amazing!<\/p>\n<h2>Web Speech API: Speech Synthesis<\/h2>\n<p>We&#8217;re diving right in with one of the more fun APIs to play around with. Did you know a browser could talk? That&#8217;s right, apart from displaying text, it can also convert that text to spoken words.<\/p>\n<p>This API has some handy use cases, like providing a simple screen reader. Granted, most visually impaired people have a more capable screen reader installed on their device. This doesn\u2019t mean that they have access to their own devices all time, and providing a simple screen reader in the browser shows you care about them.<\/p>\n<p>You can of course also use this for some fun marketing purposes, or to have an interactive assistant right there on your website.<\/p>\n<p>Don&#8217;t overdo it, though, and always ask the user if they would like some spoken words, or prefer to read text themselves.<\/p>\n<p>Before we look at how to use the Web Speech API, let&#8217;s see where we can actually use it. Currently <a href=\"https:\/\/developer.mozilla.org\/it\/docs\/Web\/API\/SpeechSynthesis\" target=\"_blank\">the API is supported<\/a> in all major browsers: Chrome, Firefox, Edge and Safari.<\/p>\n<p>Ok, it&#8217;s time to start writing some code. The following few lines of code are all that&#8217;s required to make your browser talk:<\/p>\n<p><code>const synth = window.speechSynthesis;<br \/>\nconst utterance = new SpeechSynthesisUtterance('Hey look, I can talk');<br \/>\nsynth.speak(utterance);<\/code><\/p>\n<p>We start by locating our speech synthesiser, it\u2019s located in the global window object. Let&#8217;s put it in a <code>synth<\/code> variable for easier use later on.<\/p>\n<p>The second part of the code will create a new <code>SpeechSynthesisUtterance<\/code> instance. This object will contain the text we want the browser to say, and optionally, some characteristics on how to pronounce this text.<\/p>\n<p>Once we know where to find the speech synthesiser, and we created our speech synthesis utterance, all we need to do is pass the utterance to the synthesizer. That wasn&#8217;t so difficult, was it?<\/p>\n<p>I mentioned before that the utterance instance can also contain some characteristics on how to talk. Let&#8217;s look a bit deeper into this.<\/p>\n<p>Each browser has a set of default voices we can choose from. Let&#8217;s see how you can choose another voice.<\/p>\n<p><code>const utterance = new SpeechSynthesisUtterance('Hey look, I can talk with a female voice!');<br \/>\nconst voices = synth.getVoices()<br \/>\nconst voice = voices.find(voice =&gt; voice.name === 'Fiona');<br \/>\nutterance.voice = voice<\/code><\/p>\n<p>You can find a bunch of different male and female voices, each with its own accent. From the list of available voices, I chose Fiona&#8217;s. Once you know which voice you like, it\u2019s as simple as setting that voice as the <code>voice<\/code> property of your utterance.<\/p>\n<p>It\u2019s also possible to change the voice a bit. The utterance has <code>pitch<\/code> and <code>speed<\/code> properties for you to customise.<\/p>\n<p><code>const utterance = new SpeechSynthesisUtterance('I talk slow, with a higher voice.');<br \/>\nutterance.pitch = 2;<br \/>\nutterance.rate = .7;<\/code><\/p>\n<p>Now that we&#8217;ve seen how to choose a voice and customise it, let&#8217;s throw it all together:<\/p>\n<p><code>const synth = window.speechSynthesis;<br \/>\nconst utterance = new SpeechSynthesisUtterance('Wow, this speech synthesis API is really cool!');<br \/>\nconst voices = synth.getVoices();<br \/>\nconst voice = voices.find(voice =&gt; voice.name === 'Fiona');<br \/>\nutterance.voice = voice;<br \/>\nutterance.pitch = 2;<br \/>\nutterance.rate = .7;<br \/>\nsynth.speak(utterance);<\/code><\/p>\n<p data-height=\"265\" data-theme-id=\"0\" data-slug-hash=\"GQWBbx\" data-default-tab=\"result\" data-user=\"Sambego\" data-embed-version=\"2\" data-pen-title=\"Speech Synthesis example\" class=\"codepen\">See the Pen <a href=\"https:\/\/codepen.io\/Sambego\/pen\/GQWBbx\/\">Speech Synthesis example<\/a> by Sam (<a href=\"https:\/\/codepen.io\/Sambego\">@Sambego<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p><script async src=\"https:\/\/static.codepen.io\/assets\/embed\/ei.js\"><\/script><\/p>\n<h2>Web Speech API: Speech Recognition<\/h2>\n<p>We\u2019ve seen that modern browsers are capable of talking, but did you know they are also quite capable of listening?<\/p>\n<p>You might expect something as futuristic as speech recognition to be extremely difficult, but browsers have made it really simple. Using the SpeechRecognition interface of the Web Speech API it only takes a few lines of code.<\/p>\n<p>You can use this API for a lot of cases, for example to create a simple personal assistant like Siri or Google Assistant. This assistant could help users with a more personal experience than a help section or some FAQs.<\/p>\n<p>There is a caveat when using this API: it only works when you have an active internet connection. The reason for this is that the API doesn\u2019t do its magic inside the browser. It will send a recording coming from your microphone to a server where it will analyse the sound and try to recognise the words being said. Once that server recognises some words or sentences, it will respond with a string of text, together with a percentage of how certain it is that it recognised all words correctly.<\/p>\n<p>Unfortunately, this is currently only possiblein Google Chrome, but <a href=\"https:\/\/developer.mozilla.org\/it\/docs\/Web\/API\/SpeechRecognition\" target=\"_blank\">Firefox is working on its implementation<\/a>.<\/p>\n<p>Now that you&#8217;re aware of its limitations, let&#8217;s see how we can recognise some spoken words.<\/p>\n<p><code>const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;<br \/>\nconst recognition = new SpeechRecognition();<br \/>\nrecognition.lang = 'en-US';<br \/>\nrecognition.continuous = false;<br \/>\nrecognition.interimResults = false;<br \/>\nrecognition.onresult = event =&gt; console.log(event.results[0][0].transcript);<br \/>\nrecognition.onerror = error =&gt; console.error(error);<br \/>\nrecognition.start();<\/code><\/p>\n<p>The speech recognition interfaces are currently prefixed in Chrome, so we&#8217;ll need to create a new <code>webkitSpeechRecognition<\/code> instance if <code>SpeechRecognition<\/code> is not available, which we can use to configure some parameters.<\/p>\n<p>The <code>lang<\/code> property sets the language of the text to be recognised. If this property is not set, the browser will use the HTML <code>lang<\/code> attribute value, or the user agent&#8217;s language setting when that attribute is not set.<\/p>\n<p>When setting <code>continuous<\/code> to true, the browser will listen continuously for spoken words. By default this is turned off and the API will stop listening when it\u2019s done recognising a single piece of text.<\/p>\n<p>By setting the <code>interimResults<\/code> to true, the browser will return results while it\u2019s processing. Once the API is fairly certain it has the final result, it will send it. The intermediate results will almost always contain mistakes, but it could be useful to get some early feedback.<\/p>\n<p>Of course, we want to be notified when a result is available. By setting an event handler as the <code>onresult<\/code> property, we can get the results of the API, and do something with it. The same goes for errors, we can catch them with the <code>onerror<\/code> event handler.<\/p>\n<p>All that&#8217;s left is to start listening!<\/p>\n<p data-height=\"265\" data-theme-id=\"0\" data-slug-hash=\"MQqRqM\" data-default-tab=\"result\" data-user=\"Sambego\" data-embed-version=\"2\" data-pen-title=\"Web speech recognition API\" class=\"codepen\">See the Pen <a href=\"https:\/\/codepen.io\/Sambego\/pen\/MQqRqM\/\">Web speech recognition API<\/a> by Sam (<a href=\"https:\/\/codepen.io\/Sambego\">@Sambego<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p><script async src=\"https:\/\/static.codepen.io\/assets\/embed\/ei.js\"><\/script><\/p>\n<h2>Media Recorder API<\/h2>\n<p>Video chat and voice messages are getting more common lately. Wouldn&#8217;t it be nice if there was an easy to use API to record a media stream? It turns out the Media Recorder API makes a job like this a breeze.<\/p>\n<p>We can combine <code>MediaDevices.getUserMedia()<\/code> to access the user&#8217;s webcam or microphone and the Media Recorder API to record data from these devices.<\/p>\n<p>Accessing the user&#8217;s webcam and microphone works in<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/MediaDevices\/getUserMedia%20\" target=\"_blank\"> all latest versions of all major browsers<\/a>. Recording media is <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/MediaStream_Recording_API\" target=\"_blank\">currently only possible in Chrome and Firefox<\/a>.<\/p>\n<p>To record a video, we&#8217;ll need a little bit more code than the two examples above, so let&#8217;s get started.<\/p>\n<p><code>navigator.mediaDevices.getUserMedia({<br \/>\nvideo: true,<br \/>\naudio: true,<br \/>\n}).then(stream =&gt; {<br \/>\n...<br \/>\n});<\/code><\/p>\n<p>By calling <code>getUserMedia<\/code> we ask permission to access both the user&#8217;s webcam and microphone. If you would like to use only one of them, just leave out <code>video<\/code> or <code>audio<\/code> from the config object. This will return a <code>Promise<\/code> which will resolve a media stream. We will pass this stream to our media recorder later.<\/p>\n<p>The <code>getUserMedia<\/code> method used to be available right from the navigator object. You can still find it there, but it\u2019s deprecated in favour of the method in the <code>navigator.mediaDevices<\/code> \u00a0object.<\/p>\n<p><code>const recorder = new MediaRecorder(stream);<br \/>\nrecorder.ondataavailable = saveRecordingChunk;<br \/>\nrecorder.onstop = saveRecording;<\/code><\/p>\n<p>Once we have access to the user&#8217;s microphone and video, we want to create a new <code>MediaRecorder<\/code> instance, and pass along the stream of incoming video and audio. The <code>MediaRecorder<\/code> instance has a few event handlers we can configure. We&#8217;re going to use the <code>ondataavailable<\/code> and <code>onstop<\/code> event handlers in this example.<\/p>\n<p>Every time some new data becomes available, the ondataavailable event handler will be called. In this event handler we will save the newly available data for a later use.<\/p>\n<p><code>const chunks = [];<br \/>\nconst saveRecordingChunk = event =&gt; {<br \/>\nchunks.push(event.data);<br \/>\n};<\/code><\/p>\n<p>When we stop recording, the <code>onstop<\/code> event handler will be called. We will use the chunks we saved every time some data became available to create a preview of our recording. The first thing we need to do is create a<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Blob\"> Blob<\/a> from the saved chunks. Once we have that Blob we can convert it to an encoded URL. By passing this URL as the source of an HTML5 <code>&lt;video&gt;<\/code> element, we can view our recording. Of course, if you only recorded audio, you can pass it to an HTML5 <code>&lt;audio&gt;<\/code> element.<\/p>\n<p><code>const saveRecording = event =&gt; {<br \/>\nconst recordingBlob = new Blob(chunks, {<br \/>\ntype: 'video\/webm',<br \/>\n};const recordingURL = URL.createObjectURL(recordingBlob);<br \/>\ndocument.querySelector('video').src = recordingURL;<br \/>\n};<\/code><\/p>\n<p>Now all that&#8217;s left to do is to actually start recording.<\/p>\n<p><code>recorder.start();<\/code><\/p>\n<p data-height=\"265\" data-theme-id=\"0\" data-slug-hash=\"LQJoVL\" data-default-tab=\"result\" data-user=\"Sambego\" data-embed-version=\"2\" data-pen-title=\"Media recorder API\" class=\"codepen\">See the Pen <a href=\"https:\/\/codepen.io\/Sambego\/pen\/LQJoVL\/\">Media recorder API<\/a> by Sam (<a href=\"https:\/\/codepen.io\/Sambego\">@Sambego<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p><script async src=\"https:\/\/static.codepen.io\/assets\/embed\/ei.js\"><\/script><\/p>\n<h2>Notification API<\/h2>\n<p>When you use a web app and that app wants to send you a notification about something, it usually sends an email with a call to action. If you&#8217;ve got the mobile app installed, you might also get a push notification. These are all convenient ways of alerting a user that something has happened, and encourage them to take some action. But what if I told you the web can also send notifications? I&#8217;m not talking about the Facebook notification flyout, but actual native toast messages.<\/p>\n<p align=\"center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-18228\" src=\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/notification-1.png\" alt=\"A browser notification from Firefox\" width=\"650\" height=\"167\" \/><br \/><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-18230\" src=\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/notification-2.png\" alt=\"A browser notification from Chrome\" width=\"366\" height=\"100\" \/><\/p>\n<p>The browser support for creating notifications is pretty good. All major desktop browsers are able to do so, and most mobile browsers as well. <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Notification\/Notification\" target=\"_blank\">Only Safari on iOS does not support this yet.<\/a><\/p>\n<p>To send these notifications, we first need to get permission from the user. Asking for permissions will usually happen automatically when you use a certain browser API, but not when trying to send a notification. We need to explicitly ask for permission. Once the user has given the permission, the browser will remember it and the permission will stay valid until the user revokes it.<\/p>\n<p><code>Notification.requestPermission(permission =&gt; {<br \/>\nif (permission === 'granted') {<br \/>\n\/\/ We can send a notification here<br \/>\n}<br \/>\n});<\/code><\/p>\n<p>Now that the user has granted us permission to send notifications, we can create one.<\/p>\n<p><code>const notification = new Notification('Can I get your attention please?', {<br \/>\nbody: `Something important has happened, and I need your attention.`,<br \/>\nicon: 'url\/to\/a\/cat\/icon.png',<br \/>\n});<\/code><\/p>\n<p>When creating a new <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/notification\" target=\"_blank\">Notification instance<\/a>, you can pass along a title, and some other optional parameters like a body text or icon to easily identify the origin of the notification. The browser will add the URL from which the notification has been sent.<\/p>\n<p>As mentioned before, we don\u2019t only want to focus the user&#8217;s attention on something that has happened. We want the user to respond to that event as well. Now that we created a new Notification instance, it\u2019s easy to add a click event handler to it. This will allow the user to click on the notification and execute an action.<\/p>\n<p><code>notification.onclick = event =&gt; {<br \/>\n\/\/ Do something cool!<br \/>\n};<\/code><\/p>\n<p>It\u2019s important to know, there is a big difference between the push notifications you receive on your phone and the notifications we are creating here. These notifications can only be sent when the user is visiting your website or web app.<\/p>\n<p>It\u2019s possible to send push notifications from the web, using Service Workers, but I won&#8217;t go into this here, as it would require an article of its own.<\/p>\n<p data-height=\"265\" data-theme-id=\"0\" data-slug-hash=\"NyLVBW\" data-default-tab=\"result\" data-user=\"Sambego\" data-embed-version=\"2\" data-pen-title=\"Notification API\" class=\"codepen\">See the Pen <a href=\"https:\/\/codepen.io\/Sambego\/pen\/NyLVBW\/\">Notification API<\/a> by Sam (<a href=\"https:\/\/codepen.io\/Sambego\">@Sambego<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p><script async src=\"https:\/\/static.codepen.io\/assets\/embed\/ei.js\"><\/script><\/p>\n<h2>Geolocation API<\/h2>\n<p>The last API I want to talk about is the Geolocation API. As the name suggests, it allows you to identify your user&#8217;s location. Knowing your user&#8217;s location can be useful for a more personal service. For example, you could show news or events close to the location.<\/p>\n<p>Asking for your user&#8217;s permission to identify the location can be a sensitive thing to do, especially with users who value their privacy. Always consider whether it adds value to know the location or not.<\/p>\n<p>If you are wondering about the browser support for this API, I&#8217;ve got good news. <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Geolocation\" target=\"_blank\">It works in all major browsers<\/a>.<\/p>\n<p>Now that you know it\u2019s possible to ask for the user&#8217;s location, and you&#8217;ve decided it\u2019s going to make your website or web app better, let&#8217;s see how we can do so.<\/p>\n<p><code>navigator.geolocation.getCurrentPosition(position =&gt; {<br \/>\nconsole.log('Your current position:', position.coords);<br \/>\n});<\/code><\/p>\n<p>We call <code>geolocation.getCurrenctPosition<\/code>, which will return a <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Position\" target=\"_blank\">Position object<\/a>. This object contains the coordinates of the user&#8217;s location. The two most important properties of this object are <code>latitude<\/code> and <code>longitude<\/code>.<\/p>\n<p>If you&#8217;re like me (and you probably are), latitude and longitude don&#8217;t really mean much to you. Fortunately, there are a lot of services which let you convert these coordinates to a more readable result. Let&#8217;s see how we can use the <a href=\"https:\/\/developers.google.com\/maps\/\" target=\"_blank\">Google Maps API<\/a> to get a city name from these coordinates.<\/p>\n<p><code>const latLng =<br \/>\nnew maps.LatLng(coordinates.coords.latitude, coordinates.coords.longitude);<br \/>\nconst geocoder = new maps.Geocoder();<br \/>\ngeocoder.geocode({latLng}, (results, status) =&gt; {<br \/>\nif (status === maps.GeocoderStatus.OK) {<br \/>\nconsole.logs(`You current position is:<br \/>\n${results.find(result =&gt;<br \/>\nresult.types.includes('locality'))['formatted_address']}`)<br \/>\n}<br \/>\n});<\/code><\/p>\n<p>You can get more detailed information on how to use the <a href=\"https:\/\/developers.google.com\/maps\/documentation\/\" target=\"_blank\">Google Maps API on their documentation website.<\/a><\/p>\n<p data-height=\"265\" data-theme-id=\"0\" data-slug-hash=\"ZrMNVL\" data-default-tab=\"result\" data-user=\"Sambego\" data-embed-version=\"2\" data-pen-title=\"Geolocation API\" class=\"codepen\">See the Pen <a href=\"https:\/\/codepen.io\/Sambego\/pen\/ZrMNVL\/\">Geolocation API<\/a> by Sam (<a href=\"https:\/\/codepen.io\/Sambego\">@Sambego<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p><script async src=\"https:\/\/static.codepen.io\/assets\/embed\/ei.js\"><\/script><\/p>\n<h2>Conclusion<\/h2>\n<p>By showing you five things that are possible in a browser, I hope you start to see the potential of the web. Where we used to download and install heavy, platform-specific software, we are now able to visit a website. With Progressive Web Apps being the next big thing, it\u2019s also good to know that the web is more than text and forms.<\/p>\n<p>Not all of these APIs might be available in all browsers, but we need to be patient. The web is evolving at an amazing speed, and browser vendors constantly improve their products. What&#8217;s not yet possible today, might be possible in a few months.<\/p>\n<p>If you&#8217;d like to know more about what&#8217;s possible on the web, I&#8217;d suggest you dive into <a href=\"https:\/\/developer.mozilla.org\/\" target=\"_blank\">the documentation on MDN<\/a> and start playing around.<\/p>\n<p>All demos for this article can be found on <a href=\"https:\/\/codepen.io\/collection\/AYewrw\/\" target=\"_blank\">CodePen<\/a>.<\/p>\n<p>Now go and impress your users with a talking browser that shows a notification of where they are!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, Sam Bellen explores some clever, but simple, JavaScript techniques that let you use your visitor&#8217;s web browser to improve their experience when visiting your website.<\/p>\n","protected":false},"author":2,"featured_media":18307,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,24],"tags":[],"class_list":{"0":"post-18223","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-guest-posts","8":"category-web-design"},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>5 things you didn&#039;t know a browser could do! - Heart Internet<\/title>\n<meta name=\"description\" content=\"In this guide, Sam Bellen explores some clever, but simple, JavaScript techniques that let you use your visitor&#039;s web browser to improve their experience when visiting your website.\" \/>\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.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"5 things you didn&#039;t know a browser could do! - Heart Internet\" \/>\n<meta property=\"og:description\" content=\"In this guide, Sam Bellen explores some clever, but simple, JavaScript techniques that let you use your visitor&#039;s web browser to improve their experience when visiting your website.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/\" \/>\n<meta property=\"og:site_name\" content=\"Heart Internet\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/heartinternet\/\" \/>\n<meta property=\"article:published_time\" content=\"2018-04-03T11:30:06+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2018\/04\/browsercando-background.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1265\" \/>\n\t<meta property=\"og:image:height\" content=\"500\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Eliot Chambers-Ostler\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@heartinternet\" \/>\n<meta name=\"twitter:site\" content=\"@heartinternet\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Eliot Chambers-Ostler\" \/>\n\t<meta name=\"twitter:label2\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/\"},\"author\":{\"name\":\"Eliot Chambers-Ostler\",\"@id\":\"https:\/\/heartblog.victory.digital\/#\/schema\/person\/58ed7f27cc0f3ab6e69135742a5eee28\"},\"headline\":\"5 things you didn&#8217;t know a browser could do!\",\"datePublished\":\"2018-04-03T11:30:06+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/\"},\"wordCount\":2211,\"commentCount\":4,\"publisher\":{\"@id\":\"https:\/\/heartblog.victory.digital\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2018\/04\/browsercando-background.jpg\",\"articleSection\":[\"Guest Posts\",\"Web Design\"],\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/\",\"url\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/\",\"name\":\"5 things you didn't know a browser could do! - Heart Internet\",\"isPartOf\":{\"@id\":\"https:\/\/heartblog.victory.digital\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2018\/04\/browsercando-background.jpg\",\"datePublished\":\"2018-04-03T11:30:06+00:00\",\"description\":\"In this guide, Sam Bellen explores some clever, but simple, JavaScript techniques that let you use your visitor's web browser to improve their experience when visiting your website.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#primaryimage\",\"url\":\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2018\/04\/browsercando-background.jpg\",\"contentUrl\":\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2018\/04\/browsercando-background.jpg\",\"width\":1265,\"height\":500},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.heartinternet.uk\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"5 things you didn&#8217;t know a browser could do!\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/heartblog.victory.digital\/#website\",\"url\":\"https:\/\/heartblog.victory.digital\/\",\"name\":\"Heart Internet\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/heartblog.victory.digital\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/heartblog.victory.digital\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/heartblog.victory.digital\/#organization\",\"name\":\"Heart Internet\",\"url\":\"https:\/\/heartblog.victory.digital\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\/\/heartblog.victory.digital\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2025\/02\/HeartInternet_Logo_Colour.webp\",\"contentUrl\":\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2025\/02\/HeartInternet_Logo_Colour.webp\",\"width\":992,\"height\":252,\"caption\":\"Heart Internet\"},\"image\":{\"@id\":\"https:\/\/heartblog.victory.digital\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/heartinternet\/\",\"https:\/\/x.com\/heartinternet\",\"https:\/\/www.linkedin.com\/company\/heart-internet-ltd\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/heartblog.victory.digital\/#\/schema\/person\/58ed7f27cc0f3ab6e69135742a5eee28\",\"name\":\"Eliot Chambers-Ostler\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\/\/heartblog.victory.digital\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2025\/08\/cropped-Eliot-96x96.jpg\",\"contentUrl\":\"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2025\/08\/cropped-Eliot-96x96.jpg\",\"caption\":\"Eliot Chambers-Ostler\"},\"url\":\"https:\/\/www.heartinternet.uk\/blog\/author\/eliot-chambers-ostler\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"5 things you didn't know a browser could do! - Heart Internet","description":"In this guide, Sam Bellen explores some clever, but simple, JavaScript techniques that let you use your visitor's web browser to improve their experience when visiting your website.","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.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/","og_locale":"en_GB","og_type":"article","og_title":"5 things you didn't know a browser could do! - Heart Internet","og_description":"In this guide, Sam Bellen explores some clever, but simple, JavaScript techniques that let you use your visitor's web browser to improve their experience when visiting your website.","og_url":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/","og_site_name":"Heart Internet","article_publisher":"https:\/\/www.facebook.com\/heartinternet\/","article_published_time":"2018-04-03T11:30:06+00:00","og_image":[{"width":1265,"height":500,"url":"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2018\/04\/browsercando-background.jpg","type":"image\/jpeg"}],"author":"Eliot Chambers-Ostler","twitter_card":"summary_large_image","twitter_creator":"@heartinternet","twitter_site":"@heartinternet","twitter_misc":{"Written by":"Eliot Chambers-Ostler","Estimated reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#article","isPartOf":{"@id":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/"},"author":{"name":"Eliot Chambers-Ostler","@id":"https:\/\/heartblog.victory.digital\/#\/schema\/person\/58ed7f27cc0f3ab6e69135742a5eee28"},"headline":"5 things you didn&#8217;t know a browser could do!","datePublished":"2018-04-03T11:30:06+00:00","mainEntityOfPage":{"@id":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/"},"wordCount":2211,"commentCount":4,"publisher":{"@id":"https:\/\/heartblog.victory.digital\/#organization"},"image":{"@id":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#primaryimage"},"thumbnailUrl":"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2018\/04\/browsercando-background.jpg","articleSection":["Guest Posts","Web Design"],"inLanguage":"en-GB","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/","url":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/","name":"5 things you didn't know a browser could do! - Heart Internet","isPartOf":{"@id":"https:\/\/heartblog.victory.digital\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#primaryimage"},"image":{"@id":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#primaryimage"},"thumbnailUrl":"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2018\/04\/browsercando-background.jpg","datePublished":"2018-04-03T11:30:06+00:00","description":"In this guide, Sam Bellen explores some clever, but simple, JavaScript techniques that let you use your visitor's web browser to improve their experience when visiting your website.","breadcrumb":{"@id":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/"]}]},{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#primaryimage","url":"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2018\/04\/browsercando-background.jpg","contentUrl":"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2018\/04\/browsercando-background.jpg","width":1265,"height":500},{"@type":"BreadcrumbList","@id":"https:\/\/www.heartinternet.uk\/blog\/5-things-you-didnt-know-a-browser-could-do\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.heartinternet.uk\/blog\/"},{"@type":"ListItem","position":2,"name":"5 things you didn&#8217;t know a browser could do!"}]},{"@type":"WebSite","@id":"https:\/\/heartblog.victory.digital\/#website","url":"https:\/\/heartblog.victory.digital\/","name":"Heart Internet","description":"","publisher":{"@id":"https:\/\/heartblog.victory.digital\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/heartblog.victory.digital\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":"Organization","@id":"https:\/\/heartblog.victory.digital\/#organization","name":"Heart Internet","url":"https:\/\/heartblog.victory.digital\/","logo":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/heartblog.victory.digital\/#\/schema\/logo\/image\/","url":"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2025\/02\/HeartInternet_Logo_Colour.webp","contentUrl":"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2025\/02\/HeartInternet_Logo_Colour.webp","width":992,"height":252,"caption":"Heart Internet"},"image":{"@id":"https:\/\/heartblog.victory.digital\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/heartinternet\/","https:\/\/x.com\/heartinternet","https:\/\/www.linkedin.com\/company\/heart-internet-ltd"]},{"@type":"Person","@id":"https:\/\/heartblog.victory.digital\/#\/schema\/person\/58ed7f27cc0f3ab6e69135742a5eee28","name":"Eliot Chambers-Ostler","image":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/heartblog.victory.digital\/#\/schema\/person\/image\/","url":"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2025\/08\/cropped-Eliot-96x96.jpg","contentUrl":"https:\/\/www.heartinternet.uk\/blog\/wp-content\/uploads\/2025\/08\/cropped-Eliot-96x96.jpg","caption":"Eliot Chambers-Ostler"},"url":"https:\/\/www.heartinternet.uk\/blog\/author\/eliot-chambers-ostler\/"}]}},"_links":{"self":[{"href":"https:\/\/www.heartinternet.uk\/blog\/wp-json\/wp\/v2\/posts\/18223","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.heartinternet.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.heartinternet.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.heartinternet.uk\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.heartinternet.uk\/blog\/wp-json\/wp\/v2\/comments?post=18223"}],"version-history":[{"count":0,"href":"https:\/\/www.heartinternet.uk\/blog\/wp-json\/wp\/v2\/posts\/18223\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.heartinternet.uk\/blog\/wp-json\/wp\/v2\/media\/18307"}],"wp:attachment":[{"href":"https:\/\/www.heartinternet.uk\/blog\/wp-json\/wp\/v2\/media?parent=18223"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.heartinternet.uk\/blog\/wp-json\/wp\/v2\/categories?post=18223"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.heartinternet.uk\/blog\/wp-json\/wp\/v2\/tags?post=18223"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}