Search Google developer videos

I built a prototype API and application for searching Google developer video transcripts and metadata:


Sample search app for Google developer videos


Screenshot of JSON response to


1. I work for a search company.

2. More and more content online is video.

3. Video is inherently opaque to textual search.

How can we navigate and search media content? Not least the thousands of videos on Google Developers, Android Developers and Chrome Developers.

Thankfully Google has a secret weapon: a crack team of transcribers who produce highly accurate, timecoded captions for Google videos. (Not  to be confused with the sometimes slightly surreal automated alternative.)

Some people prefer to access information by reading text rather than watching videos, so I also enabled access to downloadable transcripts:

The transcripts have Google Translate built in, so you can choose read them in a different language. Caption highlighting is synchronised with video playback — and you can tap or click on any part of a transcript to navigate through the video.

Web page screenshot showing transcript of Google Developer video HTTP 203: Pointer Events

HTTP 203: Pointer Events translated into French
(Apologies if the translation is dodgy…)

I hope the app and API are useful. As ever, your feedback would be much appreciated.

With some minor tweaking you could use my app and API to build search for any YouTube channels that have manually captioned videos — just tweak the channels in the code.

A quick hat-tip to the world’s transcribers, captioners and reporters.

These unsung heroes have amazing, hard-won skills! If you’ve ever seen a captioner at work at a live event, you’ll understand what a complex and difficult job it is.

Why are captions important? Because they give more people better access to media: those of us with impaired hearing, or whose first language isn’t the language of the video we’re watching.

Likewise, respect is due to the archivists who catalogue video after broadcast — the art of ‘shotlisting’. Without shotlists, history is lost (and it’s hard to resell footage…) Where was that sequence of Donald Rumsfeld getting down with Saddam Hussein? Shotlisters work long days faithfully cataloguing and timecoding news stories, often at double speed, one package (or rush) after another. One of my ex-colleagues at ITN, Jude Cowan, wrote a brilliant and moving book of poetry on the subject.


Search for something:

Transcripts for two or more videos:,3i9WFgMuKHs

Link to a query:

Data and transcript for a video:

Transcript only: or or

Multiple values — comma, semicolon or pipe delimiter, spaces OK:,iZZdhTUP5qg, iZZdhTUP5qg

Search any field for a query, spaces OK — can be a bit slow: 203

More shortcuts: c for captions, s for speaker — speakers are parsed from transcript:

Can specify ranges for commentCount, dislikeCount, favoriteCount, likeCount, viewCount:>10000

You can use any of these values to specify order:>10000&sort=viewCount

Add a hyphen for descending order:>10000&sort=-viewCount

Show items with titles that include ‘Android’ or

Items with speakers that include Reto and a title that includes Android:

Spaces are OK: Meier&title=Android

More complex stuff works too: Wear|description=Android Wear)&speakers=Reto Wear|description=Android Wear)&speakers=[Reto,Wayne]”Android Wear”|title=WebRTC Wear|description=Android Wear)&speakers=Timothy

Fuzzy matching — with apologies to Wayne, whose name I generally misspell :):

For dates, use ‘from’ and ‘to’, which can cope with anything Date can handle: // assumes text-only is a month this year 2014 // midnight, 1 January to midnight, 1 January

Get total for any quantity field — this query returns the total number of views for all videos:

Get total for any query and quantity field:

Get all individual values for any quantity field for all videos — returns an object keyed by amounts, values are number of occurrences for each amount:

Get all individual values for any quantity field for any query:

Build a chart from results (views for videos that mention ‘Chrome’):

The code

Available from GitHub:

Truth be told, it’s a bit of a dog’s dinner. I wrote most of the app and API on long flights and in the small hours under the influence of jet lag. E&OE! The JavaScript is a little… procedural, and I hereby pledge that I will mend my ways.

Issues and pull requests welcome.

There are three code directories:

app: the web client (as used at This will automatically choose the local Node middle layer (below) if run from localhost.

get: middle layer Node app to get data from the database. For testing, you can run this locally with the app running from localhost. I run the live version on Nodejitsu at, for queries like this: (same as

put: Node app to get YouTube data and transcripts, massage the response and put it in a CouchDB database at


Why didn’t you use Node on Google?

I’d like to, but Nodejitsu is very easy:

$ npm install jitsu
$ jitsu login
$ jitsu deploy
$ :)

Why didn’t you use Firebase?

I used Cloudant, which has Lucene search built in (and is based on CouchDB, and is very easy to use). Firebase can now be used with Elasticsearch, but when I started that required extra installation.

Why didn’t you just use MySQL or …

I probably should have. In fact, an SQL database with Lucene for full text search might have been much more appropriate than CouchDB. (This kind of search is actually much easier with Firebase now.)

How was CouchDB?

Good in some ways, and quick. In particular, the JSON/HTTP/REST styles feels fits well with Node/JavaScript development.

Problems came with full text search:
• Full text search is not built into CouchDB, though it can be added on with Lucene or other search engines.
• CouchDB searches return entire documents, with no ‘partial’ results. (In my case, a document represents all data for a video.) So, for example, if I want to return only captions that include ‘Android Wear’, I need to retrieve all the documents (in their entirety) that have captions that mention ‘Android Wear’ then filter.
• CouchDB search queries cannot be combined: for example, ‘get me all videos from 2013 with WebRTC in the title’. So, again, you have to add your own filter.

How big is the database?

Around 250MB, but more like 150MB without transcripts: the transcript for each document is really just a convenience to make it quick and simple to retrieve human readable transcripts, and replicates the captions (with a few tweaks).

How often is the data updated?

At present I’m updating the database manually to avoid code changes breaking it, but once the code settles down I’ll run automatic updates every (say) 30 minutes.

Why didn’t you use io.js?

No big reason. Node.js has been around longer.

How many documents have transcripts?

Last time I looked: 4312 videos, 3550 with transcripts.

How did you get the speaker names?

With a bit of sneaky regexing these are parsed from transcripts.

NB: speaker names are not parsable for many captions, so speaker search results may not always be complete.

Why are caption matches returned as span elements?

The primary use for the caption matches is within HTML markup. Returning JSON for each span might be neater and less verbose, but for most apps that would entail extra effort transforming to HTML. I could be persuaded otherwise.

How long does it take to store and index data?

This depends a lot on connectivity. From work, the app gets and inserts the video data and transcripts in under three minutes. From home, it takes about 10 minutes.

Indexing takes about 10 minutes.

What build tools do you use?

I use JSCS and JSHint with grunt and githooks to force validation on commit.

Chrome JSON formatting extensions, and were very useful.


  • I haven’t written any unit tests – yet.
  • Error handling is minimal.
  • Code refactoring is in the pipeline.
  • I don’t know a lot about working with sockets on Node, so a lot of the code has to be deliberately synchronous to avoid errors. I’m sure someone could help me…
  • The API is HTTP only as yet.
  • Use the official YouTube Captions API.
  • I wanted to use Firebase, but when I started it was a bit tricky to implement full-text search, so I opted for Cloudant. It’s now pretty simple to use Firebase with ElasticSearch, so I’ll port the data at some stage.
  • Database updates are done manually at the moment — mostly because I’m worried about messing up the sample app. Easily automated.
Posted in Uncategorized | Leave a comment

High performance HTML

How can you improve the performance of web pages?

Most developers look to JavaScript and image optimisation, server configuration, file minification and concatenation – even CSS tweaks.

Poor old HTML gets neglected, despite being the core language of the web.

HTML payloads are big and getting bigger. Pages on most top-100 sites require around 40k of HTML per page. Sites such as Amazon and Yahoo use thousands of lines of HTML per page. The home page currently clocks in at a whopping 3.5K HTML elements.

Reducing HTML complexity and the number of elements in a page won’t improve parse time much – but well crafted HTML is a crucial foundation for building fast-loading pages and layouts that respond successfully to different viewport sizes.

In this article you’ll find out how to write clean, concise HTML that enables you to create content that loads fast and works well across a variety of devices. In the process, you’ll learn how to build sites and apps that are easier to debug and maintain.

There is always more than one way to write code – especially HTML. Rather than begin every sentence in this article with ‘In general …’ we’ve gone ahead and prescribed what in our experience usually works best. That doesn’t mean that every suggestion is right every time.


Sample HTML document with guidelines

HTML, CSS and JavaScript

HTML is a markup language for adding structure and meaning to content.

HTML should not be used to style content.  Don’t put text in heading tags to ‘make it bigger’ or use blockquotes just for indentation. Instead, use CSS to change the appearance and layout of elements.

The default appearance of HTML elements is defined by a browser’s default stylesheet: Chrome, Firefox, Internet Explorer and Opera each have their own. For example, in Chrome the h1 element by default is rendered as 32px bold Times.

Three general principles:

  • Use HTML for structure, CSS for presentation and JavaScript for behaviour. CSS Zen Garden (12 years old this year!) shows this separation of concerns in action.
  • Use HTML, then turn to CSS if and when required – and, if really necessary, move on to JavaScript. For example: in many cases it’s possible to use HTML for form validation and CSS or SVG for animation – without resorting to JavaScript.
  • Put CSS and JavaScript in files separate from your HTML. This enables caching and makes code easier to debug. In production, CSS and JavaScript can then be minified, concatenated and inlined as part of your build process.

Document structure

  • Use the HTML5 document type. Here’s a barebones document:
<!DOCTYPE html>

 <title>Recipes: pesto</title>



  <p>Pesto is good!</p>

  • Link to CSS files at the top of the page, in the head element like this:
  <title>My pesto recipe</title>

  <link rel="stylesheet" href="/css/global.css">
  <link rel="stylesheet" href="css/local.css">


That way, browsers have CSS information ready before parsing HTML.

  • Put JavaScript at the bottom of the page, before the closing body tag. This speeds up page load – since the browser can render the page before parsing JavaScript – and has the helpful side effect of enabling JavaScript to refer to page elements:


  <script src="/js/global.js">
  <script src="js/local.js">

  • Alternatively, use the defer and async attributes – but be aware of their behaviour: script elements with an async attribute aren’t guaranteed to be executed in order. Also consider support: async is only implemented in Internet Explorer 10 and above; defer is only partially supported prior to Internet Explorer 10.
  • Add handlers in JavaScript code. DON’T add them inline in HTML. For example, this is error prone and hard to maintain:



  <script src="js/local.js">


<body onload="init()">


  <button onclick="handleFoo()">Foo</button>



This is much better:







  <button id="foo">Foo</button>


  <script src="js/local.js">



var fooButton =
fooButton.onclick = handleFoo();



A major reason for the success of the web is that browsers handle invalid HTML. There are even standardised rules for how browsers should render invalid code.

However, this is NOT a reason to be laissez-faire. Valid HTML is easier to debug and often smaller in file size, faster and less resource-hungry to parse and render. Invalid HTML can make successful responsive design difficult to implement.

Writing valid HTML is particular important when working with templates: what seems to work OK in an isolated chunk of code may go horribly wrong in combination with other content.

  • Incorporate validation in your workflow: use validation plugins such as HTMLHint and SublimeLinter with your editor and incorporate validation in your build process using tools such as HTMLHint with Grunt. You can check code online with tools such as the W3C HTML validator, and share configuration files with project contributors.
  • Use the HTML5 document type.
  • Make sure to maintain HTML hierarchy: nest elements correctly, and make sure no elements are left unclosed. It can be helpful for debugging to add a comment to the closing tag of an element that holds a large amount of complex content – especially when using templating:
<div id="foobar">


</div> <!-- foobar ends -->
  • Make sure to add closing tags to all elements that aren’t self-closing.

For example, this will work:

<p>Pesto is good to eat...
<p>...and pesto is easy to make.

But this is less likely to go wrong, since the end of each paragraph is made explicit:

<p>Pesto is good to eat...</p>
<p>...and pesto is easy to make.</p>
  • Closing tags are not required for list items and some very clever developers believe you should leave them out. Whatever you do, make sure to close every list element:
  <li>Pine nuts
  • One place you absolutely must include closing tags is with the video and audio elements. These are not ‘self closing’:
<!-- wrong: liable to cause layout grief -->
<video src="foo.webm" />

<!-- better -->
<video src="foo.webm">
  <p>Video element not supported.</p>

Conversely, cut clutter by removing unnecessary code:

  • There is no need to add a slash to ‘self closing’ (void) elements such as <img> and <link>. (You can enjoy a comprehensive list of self-closing elements here.)
  • Boolean attributes do not have a value: if the attribute is there, it’s true. In the following example, the video element will not autoplay and will not have controls (since this is the default):

    <video src="foo.webm">

    The following example doesn’t work as expected, because the presence of an attribute forces a true value:

    <video src="foo.webm" autoplay="false" controls="false">

    This works:

    <video src="foo.webm" autoplay="true" controls="true">

    This is more readable:

    <video src="foo.webm" autoplay controls>
  • Stylesheets and scripts don’t need a type attribute: CSS and JavaScript are the defaults.
  • Omit the protocol when linking to external content: this prevents problems with mixed content. For example:
    <a href="//">Tag soup</a>

Code formatting

Consistent formatting makes HTML code easier to understand, optimise and debug.

  • Maintain an HTML style guide for project contributors (or use an existing one like Google’s).
  • Use your editor to automate code beautification. For example, in Sublime Text add a shortcut for Reindent. You can check layout with code linters such as SublimeLinter or online tools such as CSS Beautify and JS Beautifier.
  • Don’t go mad with hierarchical HTML indentation! This can easily get out of hand, so set rational defaults for when to begin an element at the left margin. Conversely, deep hierarchies may mean you need to refactor.
  • Standardise on indentation and use either spaces or tabs, not both.
  • Improve readability with sensible nesting. For example, it’s clear that this is a heading:
      <h2><a href="/contact">Contact</a><h2>

    …whereas at first glance this just looks like a link:

    <a href="/contact"><h2>Contact</h1></a>
  • Order elements in ways that won’t be a surprise to other developers – or you in six months. For example, a footer element should go at the bottom of your .html page, even though (in theory) it could be put anywhere.
  • Standardise on single or double quotes.
  • Use lowercase code for tag and attribute names. UPPERCASE IS TIRESOME:
    <A HREF="/">Home</A>

    Mixed case is EVEN worse:


Semantic markup

Semantic means ‘relating to meaning’.

HTML markup adds meaning to content: element and attribute names describe the role of content.

HTML5 introduced a number of new ‘semantic elements’ such as <header>, <footer> and <nav>.

Using the right element for the right content is good for accessibility and helps ensure your code is understandable:

  • Use <h1> (<h2>, <h3>…) for headings,  <ul> or <ol> for lists.
  • Note that <article>  headings should begin with an <h1> (reasoning here).
  • Where appropriate, use the HTML5 semantic elements such as <header>, <footer>, <nav> and <aside>.
  • Use <p> for body text, HTML5 semantic elements (or <div> as  a fallback) to structure content – not vice versa.
  • Use <em> and <strong> rather than <i> and <b>: <em> and <strong> add meaning, not styling hints.
  • With forms use the <label> element, input types, placeholder text, and the required attribute to enforce validation. (Pete LePage’s articles on Web Fundamental show how.)
  • Mixing text and elements, as children of another element, tends to lead to layout bugs. For example, this:
    <div>Name: <input type="text" id="name"></div>

    is better expressed as this:

      <label for="name">Name:</label><input type="text" id="name">

    This has a bonus side effect: the for attribute means that clicking on the label automatically throws focus onto the input element. This is particularly useful for checkboxes and radio buttons.


To reiterate: HTML should be used to add meaning and structure to content, not for styling.

  • Use <p> elements for text, not for layout. By default, <p> has margins and other styles applied by the built-in browser stylesheet.
  • Avoid using <br> for line breaks: use block elements or the CSS display property instead. The <br> should only ever be seen within text – and even then, only very rarely (for example, as a form of punctuation within poetry).
  • Avoid using the humble <hr> to add horizontal lines: CSS border-bottom is a better option. It may make sense to use <hr> to denote a thematic break.
  • Don’t use divs unnecessarily: the W3C HTML spec describes the div as ‘an element of last resort, for when no other element is suitable’ ( Style inline elements such as links and img elements with display: block, rather than putting them in divs or (worse) using <br>.
  • Learn which elements are block level, to avoid unnecessarily putting block level elements inside divs. For example, there is no need to put a list inside a div element.
  • Do not use tables for layout. Do use tables for tabular data.
  • Flex box is now widely implemented: use it.
  • Use CSS padding for padding and margin for margins: understand the box model.
  • Standardise on margins: it’s often best to add margins to the bottom and the right of elements, rather than the top or left. Whatever you do, avoid mixing top and bottom or left and right. Use the last-of-type selector to avoid redundant margins.

HTML emails

Coding for email is nothing like coding for the modern web.

We won’t go into the gruesome details here – suffice to say that best practice for HTML email coding resembles web development from the late 1990s: tables, shim GIFs, inconsistent and minimal CSS, patchy image and media support, little or no support for JavaScript, and lots of minor hacks. (For an unpleasant taster, take a look at MailChimp’s most basic template.)

More information here, here and here.


This article is about HTML, but here are some basic CSS tips:

  • Avoid inline CSS. For performance optimisation, CSS files can be inlined as part of your build process.
  • Use an ID once and once only: there should only be a single element with id=”foo”, id=”bar”, or any other ID.
  • Use classes when you want to refer to multiple elements – and take a look at BEM syntax. Where possible, use class attributes on a parent rather than children. For example:
<!-- verbose :( -->
  <li class="ingredient">Basil</li>
  <li class="ingredient">Pine nuts</li>
  <li class="ingredient">Garlic</li>
<!-- better :) -->
<ul class="ingredients">
  <li>Pine nuts</li>


Consider the range of devices, contexts and input methods that will be used to interact with your HTML:

  • Use semantic elements.
  • Provide fallbacks: add captions and subtitles with the track element, include fallback text and/or images in video and audio elements; use poster images for video; add alt attributes to every image (give the alt attribute an empty value if the image is only for decoration).
  • Add title attributes to links – but only if the title adds meaning and doesn’t just repeat the link text.
  • Use type and placeholder elements in input elements.
  • Use ARIA attributes.

Random bonus extra suggestions

  • Make sure to encode characters with special meaning in HTML, such as < and &. For example:  <title>HTML &amp; JavaScript</title>.
  • Conversely, do not unnecessarily encode characters such as en dashes (for example, 4–5 weeks) or currency symbols such as ¢ and €.
  • Add comments if and only if it’s not obvious what’s happening in code. (And bear in mind that code commenting often shows a need for refactoring – good HTML, even when it’s complex, is generally self-explanatory.)
  • Where it makes sense – with all-capitalised headings, for example – apply text case via the CSS text-transform and font-variant properties, not by entering uppercase text. You may change your mind later!  Also, if users copy text, they probably want upper and lower case. The following <h4> is displayed in small caps, but when copied will be upper and lower case.HTML:
    <h4>W3C Web Accessibility Initiative ARIA guidance</h4>


    h4 {
      font-variant: small-caps;

And finally…

Whatever you do, test!

Build HTML testing into your workflow, toolchain and deployment processes.

Test page load on a variety of devices, on large and small screens, in a variety of connectivity contexts. Try interacting with your page with a text-only browser such as Lynx, or with a screenreader such as ChromeVox. Use emulators such as Chrome Dev Tools device mode to monitor changes. Page Speed, Web Page Test and other tools can be integrated with your workflow to automate testing before or after deployment.

For more information about how to write high performance HTML, follow the links in HTML, CSS and JavaScript resources and check out the guidance on Web Fundamentals.

Posted in html5 | Tagged , , , | 33 Comments

Media Newsletter: audio, video and realtime communications

I’ll be publishing a monthly roundup of news about media tech.

Sign up at

Archive at

Media Newsletter

Media Newsletter

Posted in Uncategorized | Leave a comment

Fundamentals of video on mobile

Watch my Google I/O video: Fundamentals of video on mobile:

  • Responsive media
  • Coping with variable connectivity
  • Accessibility and fallbacks
  • Formats and codecs
Video with captions on Chrome for Android

Video with captions on Chrome for Android



Posted in Uncategorized | Leave a comment

WebRTC in the real world: signaling, TURN and STUN

New on HTML5 Rocks: a detailed look at building servers for WebRTC.

New on HTML5 Rocks: WebRTC infrastructure

Posted in Uncategorized | Leave a comment simplest possible examples of HTML, CSS and JavaScript

I’ve built a site to provide simplest possible examples of HTML, CSS and JavaScript:


  • ‘Show me the code!’
  • ‘Does technology X work on platform Y?’
  • ‘Where the heck is that Foo example I saw?’
  • A minimum of ‘huh?’
  • Short, consistent, guessable URLs with sensible shortcuts, for example redirects to
  • Easy to maintain.
  • Works well on mobile devices.


  • Oriented to modern browsers.
  • No templating.

I hope it’s useful – comments and suggestions much appreciated.

Posted in Uncategorized | Tagged , , , | 3 Comments

WebRTC in Internet Explorer with Chrome Frame

It’s now possible to use WebRTC – PeerConnection and MediaStream – in Internet Explorer with Chrome Frame.

Best of all, getUserMedia no longer requires a flag to work with the Chrome stable channel – so, if Chrome Frame is installed, getUserMedia just works!

I’ve recorded a screencast that shows how to install Chrome Frame and configure Chrome in order to use WebRTC in Internet Explorer:

First, an explanation of how Chrome Frame works.

Google Chrome Frame is an open source plug-in that seamlessly brings Google Chrome’s open web technologies and speedy JavaScript engine to Internet Explorer 6, 7, 8, or 9.

When web developers add the Chrome Frame meta element to their web page, Internet Explorer will use Chrome Frame to render the page.

There’s more information about Chrome Frame for developers at

To try out WebRTC with Chrome Frame today, you will need to use Chrome’s Dev Channel. In the future, the WebRTC APIs will be available in both Chrome and Chrome Frame’s stable channels, without requiring any flags or other user intervention.

Installation steps

1. Download Chrome’s Dev Channel browser from (This does not work with Canary.)

2. Quit all of your browsers.

3. Install Chrome’s Dev Channel.

4. Start Internet Explorer and install Chrome Frame from

5. To enable PeerConnection, you need to set a flag by using regedit to create the following entry in your registry (as ever, be careful when using regedit!):


Just to reiterate: the WebRTC APIs will be ‘flagless’ in future versions of Chrome and won’t need this kind of intervention.

6. Re-start Internet Explorer.

One tip: you need 32-bit Internet Explorer to use Chrome Frame. It’s normal to have 32-bit Internet Explorer, even for 64-bit Windows, but you may want to check. Just look in All Programs for the version named Internet Explorer!

Once you’ve set up Chrome Frame in Internet Explorer, try out the getUserMedia demo at or the WebRTC video chat application at

If you want to know more about how to implement real-time communication in your web apps, take a look at the detailed introduction to WebRTC and getUserMedia at,

Let us know how it goes!

Posted in Uncategorized | Tagged , , , , , | 1 Comment