Hello.

I am Paul Kinlan.

I lead the Chrome and the Open Web Developer Relations team at Google.

Screen recording on Android with getUserMedia and WebRTC

Reading time: 5 minutes

Finally you can record your screen directly on Android via JS... well 'finally' is a strong word. Read More

I lead the Chrome Developer Relations team at Google.

We want people to have the best experience possible on the web without having to install a native app or produce content in a walled garden.

Our team tries to make it easier for developers to build on the web by supporting every Chrome release, creating great content to support developers on web.dev, contributing to MDN, helping to improve browser compatibility, and some of the best developer tools like Lighthouse, Workbox, Squoosh to name just a few.

I love to learn about what you are building, and how I can help with Chrome or Web development in general, so if you want to chat with me directly, please feel free to book a consultation.

I'm trialing a newsletter, you can subscribe below (thank you!)

Chrome on Google Home

Reading time: 6 minutes

Welcome to the world of the headless web and a massive fudge Read More

Building a simple PubSub system in JavaScript

Reading time: 3 minutes

In this post, I share a simple client-side JavaScript PubSub system I built. Motivated by the Not-Invented-Here syndrome and the desire for independent UI components, I created a lightweight event manager called EventManager. It allows components to communicate without direct dependencies by publishing and subscribing to named events. While similar to tools like Redux, this approach avoids separate state management, leveraging the browser's existing state. The code is available on GitHub. Read More

Barcode detection using Shape Detection API

Reading time: 3 minutes

I'm excited to share that barcode detection is now available in Chrome Canary via the Shape Detection API! This feature, along with QR code detection, offers a standardized way to access device hardware and bridge the physical and digital worlds. It's especially useful for mobile, eliminating the need for special apps just to scan barcodes. The API is simple: use BarcodeDetector.detect() with an image input to get a promise resolving to a list of barcodes. I've already integrated this into my QR Code Scanner App, and the ability to use it in worker threads is a huge bonus. It's a very promising addition to the web platform and I'm looking forward to seeing what people build with it! Read More

Ideas for web apps with FFMPEG and ffmpeg.js

Reading time: 2 minutes

I've created a Progressive Web App using FFMPEG.js that applies device frames to Android screen recordings. I've also streamlined the ffmpeg.js build process. This opens up exciting possibilities for building powerful web apps for audio and video manipulation. Many existing web-based video tools are outdated and ad-heavy. I'm interested in creating smaller, focused PWAs, each performing a specific task efficiently. I'm planning to build several apps based on this, such as video trimming, format conversion, watermarking, resizing, and splicing. The codebase from my Device Frames project provides a good starting point. I invite others to collaborate on this effort. Read More

Building ffmpeg.js for Ubuntu

Reading time: 1 minute

Building ffmpeg.js, a tool I used in my project Device Frame, can be tricky if you need custom filters and encoders. This post details the steps I took to successfully build it on Ubuntu, including installing dependencies, cloning the repo, setting up Emscripten, and running the build. I also included solutions to some common errors encountered during the process. Read More

Designing a Web Push Service

Reading time: 9 minutes

This post details the creation of a generic web-push webhook endpoint. Motivated by the desire for a streamlined notification system for various web services, I built a system that allows me to receive push notifications without needing each service to individually support web push. The system consists of a front-end client, a service worker, a front-end server, a subscription service, and a send service. The front-end client manages subscriptions and provides a unique URL endpoint. The service worker displays notifications. The front-end server handles subscription data and message routing. The subscription service persists subscription information. The send service encrypts and delivers messages to the push service. While I anticipate needing to retire this as more services natively support web push, I hope this example serves as inspiration for others looking to implement similar functionality. Read More

Material colour pallette

Reading time: 4 minutes

This blog post showcases a Material Design color palette, converted from an Adobe Color (.aco) file using the Color Palette Toolkit. It's primarily for personal reference and includes a visual representation of each color along with its hex code. The palette covers a wide spectrum of colors, from vibrant reds and pinks to various shades of purple, blue, green, yellow, orange, brown, gray, black, and white. Read More

Service Worker Routing

Reading time: 3 minutes

In this post, I discuss a new routing framework I've added to my service worker. It's based on my older LeviRoutes project and allows me to handle different URL patterns separately. This is much cleaner than a complex onfetch handler, and lets me easily manage things like requests to analytics services and my caching strategy. While sw-toolbox is a great alternative, I enjoyed the flexibility and learning experience of building my own. I encourage you to check out the code and consider routing in your own service workers. Read More

My blog's Service Worker and Caching Strategy Part 2

Reading time: 2 minutes

In this follow-up post, I've revised my blog's Service Worker and caching strategy to address previous issues, particularly the Firefox incompatibility due to the use of waitUntil and a misunderstanding of cache.put. The updated strategy now correctly fetches from the network, caches the result, and serves content from the cache, falling back to the network request if not found. The code has also been improved for readability and reliability. Read More

GRPC + Google Cloud: Cannot find module grpc_node.node

Reading time: 1 minute

This is a note for how to fix the above error because it annoyed me! Read More

Face detection using Shape Detection API

Reading time: 5 minutes

I'm excited about the new experimental Shape Detection API in Chrome Canary! It provides a simple JavaScript API for face and barcode detection, leveraging underlying hardware for performance. This opens up new possibilities for web apps, from faster face detection and profile picture cropping to real-time tagging and optimized facial recognition. While currently only available in Chrome for Android (desktop support coming soon), I've shared a demo on JSBin. I also discuss strategies for progressive enhancement to ensure broader compatibility, including server-side detection, client-side JavaScript libraries, and the potential of Web Assembly. This API has the potential to revolutionize object detection performance on the web, and I'm particularly keen to see its impact on barcode scanning apps like my own QR Snapper. Read More

Custom Elements: an ecosystem still being worked out

Reading time: 9 minutes

Web Components, specifically Custom Elements, offer exciting possibilities for web development. However, the current ecosystem is still evolving and has potential downsides. The practice of namespacing custom elements (e.g., <amp-*>, <iron-*>) creates "walled gardens" that can lock developers into specific frameworks. While understandable in the early stages, this approach hinders interoperability and leads to duplicated functionality. Ideally, we should move towards a shared vocabulary of elements (like <aspect-image>) where developers choose the implementation, not the vendor-specific element name. This requires a standardized process for defining element names, interfaces, and functionality. Imagine a world where component creators define the contract (e.g., class ShareButton extends HTMLElement { ... }) and users choose their preferred implementation. This model puts developers in control and fosters a more open and interoperable web. Furthermore, meta platforms (like Facebook or WeChat) could play a role by intercepting customElements.define calls and replacing JavaScript elements with native implementations when possible. This approach requires careful consideration, but it could lead to a more streamlined and integrated user experience. Read More

Measuring the impact of autofill on your forms

Reading time: 4 minutes

Measuring the impact of autofill is crucial. In WebKit/Blink browsers, the -webkit-autofill pseudo-class helps track autofill, but it's not supported in Firefox. I've found a workaround in Firefox using the input event, checking for the absence of keyboard interaction. Ideally, a standardized :autofill pseudo-class and a dedicated onautocomplete event would simplify this process, allowing developers to measure and manage autofill effectively. Read More

Some thoughts on the microbit

Reading time: 4 minutes

I gave my son a micro:bit for his birthday, hoping to introduce him to programming. While he preferred FIFA, I ended up having a blast exploring the device myself. I found it incredibly easy to use and a perfect starting point for hardware and software programming. I even coded a (buggy) Breakout clone to test its capabilities! While the web editor is excellent, I believe integrating WebUSB for direct deployment and improving debugging capabilities would greatly enhance the experience. Read More

Waiting for an element to be created

Reading time: 2 minutes

In my quest to understand how to detect when a field has been autofilled, I needed a way to monitor the events of an element that doesn't exist yet. I created a helper function, waitForElement, that uses MutationObserver to wait for an element with a specific ID to be added to the DOM. Once the element is added, the promise resolves and returns the element. This, combined with my previously created monitorEvents function, allows me to start logging events on dynamically created elements, getting me closer to solving the autofill detection puzzle. Read More

Monitor all Events on an Element

Reading time: 1 minute

I needed to figure out how to monitor events on an element (like when a field is autofilled) and Chrome DevTools has a monitorEvents function, but Firefox doesn't. Since I couldn't find an equivalent in Firefox DevTools, I created my own JavaScript function that iterates through an element's properties, finds event listeners (e.g., "onclick"), extracts the event name (e.g., "click"), and attaches a console logger to each event. The code snippet and a corresponding gist are provided. Read More

Simple sharing on the web with navigator.share

Reading time: 2 minutes

I'm excited to share a new, simple API for sharing on the web called navigator.share! It's available in Chrome Dev Channel on Android and allows websites to connect with native apps for sharing. This is a step towards a better inter-app communication system, simplifying sharing and potentially extending to other app interactions. You can try it now on my blog by clicking the share button. I've updated my blog to use it, falling back to my existing solution if the API isn't available. Check out the ChromeStatus page and other linked resources for more information and give us feedback! Read More

Use-cases for sockets API on the web

Reading time: 2 minutes

There's a growing interest in using socket APIs directly within web browsers for various applications, both client-side and server-side. This post lists potential use-cases for outgoing and incoming socket connections, eliminating the need for proxying through web servers. Examples include email clients connecting directly to IMAP/POP3/SMTP, SSH/RDP clients, real-time communication tools like IRC and XMPP, P2P applications like BitTorrent, and direct connections to servers for various purposes like video streaming, Bitcoin, and game multiplayer functionality. For incoming connections, use-cases include hosting servers for many of the aforementioned services (IRC, BitTorrent, HTTP) directly within the browser. Read More

The Headless Web

Reading time: 18 minutes

Do we need a browser in the future? Read More