summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/docs/experiments.rst
blob: b4fabc8f7a0f6f1751c585a19b52bbf5e54d596b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
Extensions & Experiments
========================

This document describes address bar extensions and experiments: what they are,
how to run them, how to write them, and the processes involved in each.

The primary purpose right now for writing address bar extensions is to run
address bar experiments. But extensions are useful outside of experiments, and
not all experiments use extensions.

Like all Firefox extensions, address bar extensions use the WebExtensions_
framework.

.. _WebExtensions: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions

.. contents::
   :depth: 2


WebExtensions
-------------

**WebExtensions** is the name of Firefox's extension architecture. The "web"
part of the name hints at the fact that Firefox extensions are built using Web
technologies: JavaScript, HTML, CSS, and to a certain extent the DOM.

Individual extensions themselves often are referred to as *WebExtensions*. For
clarity and conciseness, this document will refer to WebExtensions as
*extensions*.

Why are we interested in extensions? Mainly because they're a powerful way to
run experiments in Firefox. See Experiments_ for more on that. In addition, we'd
also like to build up a robust set of APIs useful to extension authors, although
right now the API can only be used by Mozilla extensions.

WebExtensions are introduced and discussed in detail on `MDN
<WebExtensions_>`__. You'll need a lot of that knowledge in order to build
address bar extensions.

Developing Address Bar Extensions
---------------------------------

Overview
~~~~~~~~

The address bar WebExtensions API currently lives in two API namespaces,
``browser.urlbar`` and ``browser.experiments.urlbar``. The reason for this is
historical and is discussed in the `Developing Address Bar Extension APIs`_
section. As a consumer of the API, there are only two important things you need
to know:

* There's no meaningful difference between the APIs of the two namespaces.
  Their kinds of functions, events, and properties are similar.  You should
  think of the address bar API as one single API that happens to be split into
  two namespaces.

* However, there is a big difference between the two when it comes to setting up
  your extension to use them. This is discussed next.

The ``browser.urlbar`` API namespace is built into Firefox. It's a
**privileged API**, which means that only Mozilla-signed and temporarily
installed extensions can use it. The only thing your Mozilla extension needs to
do in order to use it is to request the ``urlbar`` permission in its
manifest.json, as illustrated `here <urlbarPermissionExample_>`__.

In contrast, the ``browser.experiments.urlbar`` API namespace is bundled inside
your extension. APIs that are bundled inside extensions are called
**experimental APIs**, and the extensions in which they're bundled are called
**WebExtension experiments**. As with privileged APIs, experimental APIs are
available only to Mozilla-signed and temporarily installed extensions.
("WebExtension experiments" is a term of art and shouldn't be confused with the
general notion of experiments that happen to use extensions.) For more on
experimental APIs and WebExtension experiments, see the `WebExtensions API
implementation documentation <webextAPIImplBasicsDoc_>`__.

Since ``browser.experiments.urlbar`` is bundled inside your extension, you'll
need to include it in your extension's repo by doing the following:

1. The implementation consists of two files, api.js_ and schema.json_. In your
   extension repo, create a *experiments/urlbar* subdirectory and copy the
   files there. See `this repo`__ for an example.

2. Add the following ``experiment_apis`` key to your manifest.json (see here__
   for an example in context)::

     "experiment_apis": {
       "experiments_urlbar": {
         "schema": "experiments/urlbar/schema.json",
         "parent": {
           "scopes": ["addon_parent"],
           "paths": [["experiments", "urlbar"]],
           "script": "experiments/urlbar/api.js"
         }
       }
     }

As mentioned, only Mozilla-signed and temporarily installed extensions can use
these two API namespaces. For information on running the extensions you develop
that use these namespaces, see `Running Address Bar Extensions`_.

.. _urlbarPermissionExample: https://github.com/0c0w3/urlbar-top-sites-experiment/blob/ac1517118bb7ee165fb9989834514b1082575c10/src/manifest.json#L24
.. _webextAPIImplBasicsDoc: https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/basics.html
.. _api.js: https://searchfox.org/mozilla-central/source/browser/components/urlbar/tests/ext/api.js
.. _schema.json: https://searchfox.org/mozilla-central/source/browser/components/urlbar/tests/ext/schema.json
__ https://github.com/0c0w3/dynamic-result-type-extension/tree/master/src/experiments/urlbar
__ https://github.com/0c0w3/dynamic-result-type-extension/blob/0987da4b259b9fcb139b31d771883a2f822712b5/src/manifest.json#L28

browser.urlbar
~~~~~~~~~~~~~~

Currently the only documentation for ``browser.urlbar`` is its `schema
<urlbar.json_>`__. Fortunately WebExtension schemas are JSON and aren't too hard
to read. If you need help understanding it, see the `WebExtensions API
implementation documentation <webextAPIImplDoc_>`__.

For examples on using the API, see the Cookbook_ section.

.. _urlbar.json: https://searchfox.org/mozilla-central/source/browser/components/extensions/schemas/urlbar.json

browser.experiments.urlbar
~~~~~~~~~~~~~~~~~~~~~~~~~~

As with ``browser.urlbar``, currently the only documentation for
``browser.experiments.urlbar`` is its schema__. For examples on using the API,
see the Cookbook_ section.

__ https://searchfox.org/mozilla-central/source/browser/components/urlbar/tests/ext/schema.json

Workflow
~~~~~~~~

The web-ext_ command-line tool makes the extension-development workflow very
simple. Simply start it with the *run* command, passing it the location of the
Firefox binary you want to use. web-ext will launch your Firefox and remain
running until you stop it, watching for changes you make to your extension's
files. When it sees a change, it automatically reloads your extension — in
Firefox, in the background — without your having to do anything. It's really
nice.

The `web-ext documentation <web-ext commands_>`__ lists all its options, but
here are some worth calling out for the *run* command:

``--browser-console``
  Automatically open the browser console when Firefox starts. Very useful for
  watching your extension's console logging. (Make sure "Show Content Messages"
  is checked in the console.)

``-p``
  This option lets you specify a path to a profile directory.

``--keep-profile-changes``
  Normally web-ext doesn't save any changes you make to the profile. Use this
  option along with ``-p`` to reuse the same profile again and again.

``--verbose``
  web-ext suppresses Firefox messages in the terminal unless you pass this
  option. If you've added some ``dump`` calls in Firefox because you're working
  on a new ``browser.urlbar`` API, for example, you won't see them without this.

web-ext also has a *build* command that packages your extension's files into a
zip file. The following *build* options are useful:

``--overwrite-dest``
  Without this option, web-ext won't overwrite a zip file it previously created.

web-ext can load its configuration from your extension's package.json. That's
the recommended way to configure it. Here's an example__.

Finally, web-ext can also sign extensions, but if you're developing your
extension for an experiment, you'll use a different process for signing. See
`The Experiment Development Process`_.

.. _web-ext: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Getting_started_with_web-ext
.. _web-ext commands: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/web-ext_command_reference
__ https://github.com/0c0w3/urlbar-top-sites-experiment/blob/6681a7126986bc2565d036b888cb5b8807397ce5/package.json#L7

Automated Tests
~~~~~~~~~~~~~~~

It's possible to write `browser chrome mochitests`_ for your extension the same
way we write tests for Firefox. One of the example extensions linked throughout
this document includes a test_, for instance.

See the readme in the example-addon-experiment_ repo for a workflow.

.. _browser chrome mochitests: https://developer.mozilla.org/en-US/docs/Mozilla/Browser_chrome_tests
.. _test: https://github.com/0c0w3/urlbar-top-sites-experiment/blob/master/tests/tests/browser/browser_urlbarTopSitesExtension.js

Cookbook
~~~~~~~~

*To be written.* For now, you can find example uses of ``browser.experiments.urlbar`` and ``browser.urlbar`` in the following repos:

* https://github.com/mozilla-extensions/firefox-quick-suggest-weather
* https://github.com/0c0w3/urlbar-tips-experiment
* https://github.com/0c0w3/urlbar-top-sites-experiment
* https://github.com/0c0w3/urlbar-search-interventions-experiment

Further Reading
~~~~~~~~~~~~~~~

`WebExtensions on MDN <WebExtensions_>`__
  The place to learn about developing WebExtensions in general.

`Getting started with web-ext <web-ext_>`__
  MDN's tutorial on using web-ext.

`web-ext command reference <web-ext commands_>`__
  MDN's documentation on web-ext's commands and their options.

Developing Address Bar Extension APIs
-------------------------------------

Built-In APIs vs. Experimental APIs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Originally we developed the address bar extension API in the ``browser.urlbar``
namespace, which is built into Firefox as discussed above. By "built into
Firefox," we mean that the API is developed in `mozilla-central
<urlbar.json_>`__ and shipped inside Firefox just like any other Firefox
feature. At the time, that seemed like the right thing to do because we wanted
to build an API that ultimately could be used by all extension authors, not only
Mozilla.

However, there were a number of disadvantages to this development model. The
biggest was that it tightly coupled our experiments to specific versions of
Firefox. For example, if we were working on an experiment that targeted Firefox
72, then any APIs used by that experiment needed to land and ship in 72. If we
weren't able to finish an API by the time 72 shipped, then the experiment would
have to be postponed until 73. Our experiment development timeframes were always
very short because we always wanted to ship our experiments ASAP. Often we
targeted the Firefox version that was then in Nightly; sometimes we even
targeted the version in Beta. Either way, it meant that we were always uplifting
patch after patch to Beta. This tight coupling between Firefox versions and
experiments erased what should have been a big advantage of implementing
experiments as extensions in the first place: the ability to ship experiments
outside the usual cyclical release process.

Another notable disadvantage of this model was just the cognitive weight of the
idea that we were developing APIs not only for ourselves and our experiments but
potentially for all extensions. This meant that not only did we have to design
APIs to meet our immediate needs, we also had to imagine use cases that could
potentially arise and then design for them as well.

For these reasons, we stopped developing ``browser.urlbar`` and created the
``browser.experiments.urlbar`` experimental API. As discussed earlier,
experimental APIs are APIs that are bundled inside extensions. Experimental APIs
can do anything that built-in APIs can do with the added flexibility of not
being tied to specific versions of Firefox.

Adding New APIs
~~~~~~~~~~~~~~~

All new address bar APIs should be added to ``browser.experiments.urlbar``.
Although this API does not ship in Firefox, it's currently developed in
mozilla-central, in `browser/components/urlbar/tests/ext/ <extDirectory_>`__ --
note the "tests" subdirectory. Developing it in mozilla-central lets us take
advantage of our usual build and testing infrastructure. This way we have API
tests running against each mozilla-central checkin, against all versions of
Firefox that are tested on Mozilla's infrastructure, and we're alerted to any
breaking changes we accidentally make. When we start a new extension repo, we
copy schema.json and api.js to it as described earlier (or clone an example repo
with up-to-date copies of these files).

Generally changes to the API should be reviewed by someone on the address bar
team and someone on the WebExtensions team. Shane (mixedpuppy) is a good
contact.

.. _extDirectory: https://searchfox.org/mozilla-central/source/browser/components/urlbar/tests/ext/

Anatomy of an API
~~~~~~~~~~~~~~~~~

Roughly speaking, a WebExtensions API implementation comprises three different
pieces:

Schema
  The schema declares the functions, properties, events, and types that the API
  makes available to extensions. Schemas are written in JSON.

  The ``browser.experiments.urlbar`` schema is schema.json_, and the
  ``browser.urlbar`` schema is urlbar.json_.

  For reference, the schemas of built-in APIs are in
  `browser/components/extensions/schemas`_ and
  `toolkit/components/extensions/schemas`_.

  .. _browser/components/extensions/schemas: https://searchfox.org/mozilla-central/source/browser/components/extensions/schemas/
  .. _toolkit/components/extensions/schemas: https://searchfox.org/mozilla-central/source/toolkit/components/extensions/schemas/

Internals
  Every API hooks into some internal part of Firefox. For the address bar API,
  that's the Urlbar implementation in `browser/components/urlbar`_.

  .. _browser/components/urlbar: https://searchfox.org/mozilla-central/source/browser/components/urlbar/

Glue
  Finally, there's some glue code that implements everything declared in the
  schema. Essentially, this code mediates between the previous two pieces. It
  translates the function calls, property accesses, and event listener
  registrations made by extensions using the public-facing API into terms that
  the Firefox internals understand, and vice versa.

  For ``browser.experiments.urlbar``, this is api.js_, and for
  ``browser.urlbar``, it's ext-urlbar.js_.

  For reference, the implementations of built-in APIs are in
  `browser/components/extensions`_ and `toolkit/components/extensions`_, in the
  *parent* and *child* subdirecties.  As you might guess, code in *parent* runs
  in the main process, and code in *child* runs in the extensions process.
  Address bar APIs deal with browser chrome and their implementations therefore
  run in the parent process.

  .. _ext-urlbar.js: https://searchfox.org/mozilla-central/source/browser/components/extensions/parent/ext-urlbar.js
  .. _browser/components/extensions: https://searchfox.org/mozilla-central/source/browser/components/extensions/
  .. _toolkit/components/extensions: https://searchfox.org/mozilla-central/source/toolkit/components/extensions/

Keep in mind that extensions run in a different process from the main process.
That has implications for your APIs. They'll generally need to be async, for
example.

Further Reading
~~~~~~~~~~~~~~~

`WebExtensions API implementation documentation <webextAPIImplDoc_>`__
  Detailed info on implementing a WebExtensions API.

.. _webextAPIImplDoc: https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/

Running Address Bar Extensions
------------------------------

As discussed above, ``browser.experiments.urlbar`` and ``browser.urlbar`` are
privileged APIs. There are two different points to consider when it comes to
running an extension that uses privileged APIs: loading the extension in the
first place, and granting it access to privileged APIs. There's a certain bar
for loading any extension regardless of its API usage that depends on its signed
state and the Firefox build you want to run it in. There's yet a higher bar for
granting it access to privileged APIs. This section discusses how to load
extensions so that they can access privileged APIs.

Since we're interested in extensions primarily for running experiments, there
are three particular signed states relevant to us:

Unsigned
  There are two ways to run unsigned extensions that use privileged APIs.

  They can be loaded temporarily using a Firefox Nightly build or
  Developer Edition but not Beta or Release [source__], and the
  ``extensions.experiments.enabled`` preference must be set to true [source__].
  You can load extensions temporarily by visiting
  about:debugging#/runtime/this-firefox and clicking "Load Temporary Add-on."
  `web-ext <Workflow_>`__ also loads extensions temporarily.

  __ https://searchfox.org/mozilla-central/rev/053826b10f838f77c27507e5efecc96e34718541/toolkit/components/extensions/Extension.jsm#1884
  __ https://searchfox.org/mozilla-central/rev/014fe72eaba26dcf6082fb9bbaf208f97a38594e/toolkit/mozapps/extensions/internal/AddonSettings.jsm#93

  They can be also be loaded normally (not temporarily) in a custom build where
  the build-time setting ``AppConstants.MOZ_REQUIRE_SIGNING`` [source__, source__]
  and ``xpinstall.signatures.required`` pref are both false. As in the previous
  paragraph, such builds include Nightly and Developer Edition but not Beta or
  Release [source__]. In addition, your custom build must modify the
  ``Extension.isPrivileged`` getter__ to return true. This getter determines
  whether an extension can access privileged APIs.

  __ https://searchfox.org/mozilla-central/rev/053826b10f838f77c27507e5efecc96e34718541/toolkit/mozapps/extensions/internal/XPIProvider.jsm#2382
  __ https://searchfox.org/mozilla-central/rev/053826b10f838f77c27507e5efecc96e34718541/toolkit/mozapps/extensions/internal/AddonSettings.jsm#36
  __ https://searchfox.org/mozilla-central/search?q=MOZ_REQUIRE_SIGNING&case=false&regexp=false&path=
  __ https://searchfox.org/mozilla-central/rev/053826b10f838f77c27507e5efecc96e34718541/toolkit/components/extensions/Extension.jsm#1874

  Extensions remain unsigned as you develop them. See the Workflow_ section for
  more.

Signed for testing (Signed for QA)
  Signed-for-testing extensions that use privileged APIs can be run using the
  same techniques for running unsigned extensions.

  They can also be loaded normally (not temporarily) if you use a Firefox build
  where the build-time setting ``AppConstants.MOZ_REQUIRE_SIGNING`` is false and
  you set the ``xpinstall.signatures.dev-root`` pref to true
  [source__]. ``xpinstall.signatures.dev-root`` does not exist by default and
  must be created.

  __ https://searchfox.org/mozilla-central/rev/053826b10f838f77c27507e5efecc96e34718541/toolkit/mozapps/extensions/internal/XPIInstall.jsm#262

  You encounter extensions that are signed for testing when you are writing
  extensions for experiments. See the Experiments_ section for details.

  "Signed for QA" is another way of referring to this signed state.

Signed for release
  Signed-for-release extensions that use privileged APIs can be run in any
  Firefox build with no special requirements.

  You encounter extensions that are signed for release when you are writing
  extensions for experiments. See the Experiments_ section for details.

.. important::
  To see console logs from extensions in the browser console, select the "Show
  Content Messages" option in the console's settings. This is necessary because
  extensions run outside the main process.

Experiments
-----------

**Experiments** let us try out ideas in Firefox outside the usual release cycle
and on particular populations of users.

For example, say we have a hunch that the top sites shown on the new-tab page
aren't very discoverable, so we want to make them more visible. We have one idea
that might work — show them every time the user begins an interaction with the
address bar — but we aren't sure how good an idea it is. So we test it. We write
an extension that does just that, make sure it collects telemetry that will help
us answer our question, ship it outside the usual release cycle to a small
percentage of Beta users, collect and analyze the telemetry, and determine
whether the experiment was successful. If it was, then we might want to ship the
feature to all Firefox users.

Experiments sometimes are also called **studies** (not to be confused with *user
studies*, which are face-to-face interviews with users conducted by user
researchers).

There are two types of experiments:

Pref-flip experiments
  Pref-flip experiments are simple. If we have a fully baked feature in the
  browser that's preffed off, a pref-flip experiment just flips the pref on,
  enabling the feature for users running the experiment. No code is required.
  We tell the experiments team the name of the pref we want to flip, and they
  handle it.

  One important caveat to pref-flip studies is that they're currently capable of
  flipping only a single pref. There's an extension called Multipreffer_ that
  can flip multiple prefs, though.

  .. _Multipreffer: https://github.com/mozilla/multipreffer

Add-on experiments
  Add-on experiments are much more complex but much more powerful. (Here
  *add-on* is a synonym for extension.) They're the type of experiments that
  this document has been discussing all along.

  An add-on experiment is shipped as an extension that we write and that
  implements the experimental feature we want to test. To reiterate, the
  extension is a WebExtension and uses WebExtensions APIs. If the current
  WebExtensions APIs do not meet the needs of your experiment, then you must
  create either experimental or built-in APIs so that your extension can use
  them. If necessary, you can make any new built-in APIs privileged so that they
  are available only to Mozilla extensions.

  An add-on experiment can collect additional telemetry that's not collected in
  the product by using the privileged ``browser.telemetry`` WebExtensions API,
  and of course the product will continue to collect all the telemetry it
  usually does. The telemetry pings from users running the experiment will be
  correlated with the experiment with no extra work on our part.

A single experiment can deliver different UXes to different groups of users
running the experiment. Each group or UX within an experiment is called a
**branch**. Experiments often have two branches, control and treatment. The
**control branch** actually makes no UX changes. It may capture additional
telemetry, though. Think of it as the control in a science experiment. It's
there so we can compare it to data from the **treatment branch**, which does
make UX changes. Some experiments may require multiple treatment branches, in
which case the different branches will have different names. Add-on experiments
can implement all branches in the same extension or each branch in its own
extension.

Experiments are delivered to users by a system called **Normandy**. Normandy
comprises a client side that lives in Firefox and a server side. In Normandy,
experiments are defined server-side in files called **recipes**. Recipes include
information about the experiment like the Firefox release channel and version
that the experiment targets, the number of users to be included in the
experiment, the branches in the experiment, the percentage of users on each
branch, and so on.

Experiments are tracked by Mozilla project management using a system called
Experimenter_.

Finally, there was an older version of the experiments program called
**Shield**. Experiments under this system were called **Shield studies** and
could be be shipped as extensions too.

.. _Experimenter: https://experimenter.services.mozilla.com/

Further Reading
~~~~~~~~~~~~~~~

`Pref-Flip and Add-On Experiments <https://mana.mozilla.org/wiki/pages/viewpage.action?spaceKey=FIREFOX&title=Pref-Flip+and+Add-On+Experiments>`__
  A comprehensive document on experiments from the Experimenter team. See the
  child pages in the sidebar, too.

`Client Implementation Guidelines for Experiments <https://docs.telemetry.mozilla.org/cookbooks/client_guidelines.html>`_
  Relevant documentation from the telemetry team.

#ask-experimenter Slack channel
  A friendly place to get answers to your experiment questions.

The Experiment Development Process
----------------------------------

This section describes an experiment's life cycle.

1. Experiments usually originate with product management and UX. They're
   responsible for identifying a problem, deciding how an experiment should
   approach it, the questions we want to answer, the data we need to answer
   those questions, the user population that should be enrolled in the
   experiment, the definition of success, and so on.

2. UX makes a spec that describes what the extension looks like and how it
   behaves.

3. There's a kickoff meeting among the team to introduce the experiment and UX
   spec. It's an opportunity for engineering to ask questions of management, UX,
   and data science. It's really important for engineering to get a precise and
   accurate understanding of how the extension is supposed to behave — right
   down to the UI changes — so that no one makes erroneous assumptions during
   development.

4. At some point around this time, the team (usually management) creates a few
   artifacts to track the work and facilitate communication with outside teams
   involved in shipping experiments. They include:

   * A page on `Experimenter <Experiments_>`__
   * A QA PI (product integrity) request so that QA resources are allocated
   * A bug in `Data Science :: Experiment Collaboration`__ so that data science
     can track the work and discuss telemetry (engineering might file this one)

   __ https://bugzilla.mozilla.org/enter_bug.cgi?assigned_to=nobody%40mozilla.org&bug_ignored=0&bug_severity=normal&bug_status=NEW&bug_type=task&cf_firefox_messaging_system=---&cf_fx_iteration=---&cf_fx_points=---&comment=%23%23%20Brief%20Description%20of%20the%20request%20%28required%29%3A%0D%0A%0D%0A%23%23%20Business%20purpose%20for%20this%20request%20%28required%29%3A%0D%0A%0D%0A%23%23%20Requested%20timelines%20for%20the%20request%20or%20how%20this%20fits%20into%20roadmaps%20or%20critical%20decisions%20%28required%29%3A%0D%0A%0D%0A%23%23%20Links%20to%20any%20assets%20%28e.g%20Start%20of%20a%20PHD%2C%20BRD%3B%20any%20document%20that%20helps%20describe%20the%20project%29%3A%0D%0A%0D%0A%23%23%20Name%20of%20Data%20Scientist%20%28If%20Applicable%29%3A%0D%0A%0D%0A%2APlease%20note%20if%20it%20is%20found%20that%20not%20enough%20information%20has%20been%20given%20this%20will%20delay%20the%20triage%20of%20this%20request.%2A&component=Experiment%20Collaboration&contenttypemethod=list&contenttypeselection=text%2Fplain&filed_via=standard_form&flag_type-4=X&flag_type-607=X&flag_type-800=X&flag_type-803=X&flag_type-936=X&form_name=enter_bug&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Unspecified&priority=--&product=Data%20Science&rep_platform=Unspecified&target_milestone=---&version=unspecified

5. Engineering breaks down the work and files bugs. There's another engineering
   meeting to discuss the breakdown, or it's discussed asynchronously.

6. Engineering sets up a GitHub repo for the extension. See `Implementing
   Experiments`_ for an example repo you can clone to get started. Disable
   GitHub Issues on the repo so that QA will file bugs in Bugzilla instead of
   GitHub. There's nothing wrong with GitHub Issues, but our team's project
   management tracks all work through Bugzilla. If it's not there, it's not
   captured.

7. Engineering or management fills out the Add-on section of the Experimenter
   page as much as possible at this point. "Active Experiment Name" isn't
   necessary, and "Signed Release URL" won't be available until the end of the
   process.

8. Engineering implements the extension and any new WebExtensions APIs it
   requires.

9. When the extension is done, engineering or management clicks the "Ready for
   Sign-Off" button on the Experimenter page. That changes the page's status
   from "Draft" to "Ready for Sign-Off," which allows QA and other teams to sign
   off on their portions of the experiment.

10. Engineering requests the extension be signed "for testing" (or "for
    QA"). Michael (mythmon) from the Experiments team and Rehan (rdalal) from
    Services Engineering are good contacts. Build the extension zip file using
    web-ext as discussed in Workflow_. Attach it to a bug (a metabug for
    implementing the extension, for example), needinfo Michael or Rehan, and ask
    him to sign it. He'll attach the signed version to the bug. If neither
    Michael nor Rehan is available, try asking in the #ask-experimenter Slack
    channel.

11. Engineering sends QA the link to the signed extension and works with them to
    resolve bugs they find.

12. When QA signs off, engineering asks Michael to sign the extension "for
    release" using the same needinfo process described earlier.

13. Paste the URL of the signed extension in the "Signed Release URL" textbox of
    the Add-on section of the Experimenter page.

14. Other teams sign off as they're ready.

15. The experiment ships! 🎉


Implementing Experiments
------------------------

This section discusses how to implement add-on experiments. Pref-flip
experiments are much simpler and don't need a lot of explanation. You should be
familiar with the concepts discussed in the `Developing Address Bar Extensions`_
and `Running Address Bar Extensions`_ sections before reading this one.

The most salient thing about add-on experiments is that they're implemented
simply as privileged extensions. Other than being privileged and possibly
containing bundled experimental APIs, they're similar to all other extensions.

The `top-sites experiment extension <topSites_>`__ is an example of a real,
shipped experiment.

.. _topSites: https://github.com/0c0w3/urlbar-top-sites-experiment

Setup
~~~~~

example-addon-experiment_ is a repo you can clone to get started. It's geared
toward urlbar extensions and includes the stub of a browser chrome mochitest.

.. _example-addon-experiment: https://github.com/0c0w3/example-addon-experiment

browser.normandyAddonStudy
~~~~~~~~~~~~~~~~~~~~~~~~~~

As discussed in Experiments_, an experiment typically has more than one branch
so that it can test different UXes. The experiment's extension(s) needs to know
the branch the user is enrolled in so that it can behave appropriately for the
branch: show the user the proper UX, collect the proper telemetry, and so on.

This is the purpose of the ``browser.normandyAddonStudy`` WebExtensions API.
Like ``browser.urlbar``, it's a privileged API available only to Mozilla
extensions.

Its schema is normandyAddonStudy.json_.

It's a very simple API. The primary function is ``getStudy``, which returns the
study the user is currently enrolled in or null if there isn't one. (Recall that
*study* is a synonym for *experiment*.) One of the first things an experiment
extension typically does is to call this function.

The Normandy client in Firefox will keep an experiment extension installed only
while the experiment is active. Therefore, ``getStudy`` should always return a
non-null study object. Nevertheless, the study object has an ``active`` boolean
property that's trivial to sanity check. (The example extension does.)

The more important property is ``branch``, the name of the branch that the user
is enrolled in. Your extension should use it to determine the appropriate UX.

Finally, there's an ``onUnenroll`` event that's fired when the user is
unenrolled in the study. It's not quite clear in what cases an extension would
need to listen for this event given that Normandy automatically uninstalls
extensions on unenrollment. Maybe if they create some persistent state that's
not automatically undone on uninstall by the WebExtensions framework?

If your extension itself needs to unenroll the user for some reason, call
``endStudy``.

.. _normandyAddonStudy.json: https://searchfox.org/mozilla-central/source/browser/components/extensions/schemas/normandyAddonStudy.json

Telemetry
~~~~~~~~~

Experiments can capture telemetry in two places: in the product itself and
through the privileged ``browser.telemetry`` WebExtensions API. The API schema
is telemetry.json_.

The telemetry pings from users running experiments are automatically correlated
with those experiments, no extra work required. That's true regardless of
whether the telemetry is captured in the product or though
``browser.telemetry``.

The address bar has some in-product, preffed off telemetry that we want to
enable for all our experiments — at least that's the thinking as of August 2019.
It's called `engagement event telemetry`_, and it records user *engagements*
with and *abandonments* of the address bar [source__]. We added a
BrowserSetting_ on ``browser.urlbar`` just to let us flip the pref and enable
this telemetry in our experiment extensions. Call it like this::

    await browser.urlbar.engagementTelemetry.set({ value: true });

.. _telemetry.json: https://searchfox.org/mozilla-central/source/toolkit/components/extensions/schemas/telemetry.json
.. _engagement event telemetry: https://bugzilla.mozilla.org/show_bug.cgi?id=1559136
__ https://searchfox.org/mozilla-central/rev/7088fc958db5935eba24b413b1f16d6ab7bd13ea/browser/components/urlbar/UrlbarController.jsm#598
.. _BrowserSetting: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/types/BrowserSetting

Engineering Best Practices
~~~~~~~~~~~~~~~~~~~~~~~~~~

Clear up questions with your UX person early and often. There's often a gap
between what they have in their mind and what you have in yours.  Nothing wrong
with that, it's just the nature of development. But misunderstandings can cause
big problems when they're discovered late. This is especially true of UX
behaviors, as opposed to visuals or styling. It's no fun to realize at the end
of a release cycle that you've designed the wrong WebExtensions API because some
UX detail was overlooked.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Related to the previous point, make builds of your extension for your UX person
so they can test it.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Taking the previous point even further, if your experiment will require a
substantial new API(s), you might think about prototyping the experiment
entirely in a custom Firefox build before designing the API at all. Give it to
your UX person. Let them disect it and tell you all the problems with it. Fill
in all the gaps in your understanding, and then design the API. We've never
actually done this, though.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It's a good idea to work on the extension as you're designing and developing the
APIs it'll use. You might even go as far as writing the first draft of the
extension before even starting to implement the APIs. That lets you spot
problems that may not be obvious were you to design the API in isolation.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Your extension's ID should end in ``@shield.mozilla.org``. QA will flag it if it
doesn't.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Set ``"hidden": true`` in your extension's manifest.json. That hides it on
about:addons. (It can still be seen on about:studies.) QA will spot this if you
don't.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

There are drawbacks of hiding features behind prefs and enabling them in
experiment extensions. Consider not doing that if feasible, or at least weigh
these drawbacks against your expected benefits.

* Prefs stay flipped on in private windows, but experiments often have special
  requirements around private-browsing mode (PBM). Usually, they shouldn't be
  active in PBM at all, unless of course the point of the experiment is to test
  PBM. Extensions also must request PBM access ("incognito" in WebExtensions
  terms), and the user can disable access at any time. The result is that part
  of your experiment could remain enabled — the part behind the pref — while
  other parts are disabled.

* Prefs stay flipped on in safe mode, even though your extension (like all
  extensions) will be disabled. This might be a bug__ in the WebExtensions
  framework, though.

  __ https://bugzilla.mozilla.org/show_bug.cgi?id=1576997