{"id":7860,"date":"2016-07-15T08:33:58","date_gmt":"2016-07-15T15:33:58","guid":{"rendered":"http:\/\/blog.mozilla.org\/addons\/?p=7860"},"modified":"2021-03-30T14:58:47","modified_gmt":"2021-03-30T21:58:47","slug":"writing-an-opt-in-ui-for-an-extension","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/","title":{"rendered":"Writing an opt-in UI for an extension"},"content":{"rendered":"<p><em><strong>March 31, 2021 update: The content of this blog post is a little outdated. To learn more about current best practices for creating user opt-ins for extensions, please visit <a href=\"https:\/\/extensionworkshop.com\/documentation\/develop\/best-practices-for-collecting-user-data-consents\/\">Firefox Extension Workshop.<\/a> In the article &#8220;<a href=\"https:\/\/extensionworkshop.com\/documentation\/develop\/best-practices-for-collecting-user-data-consents\/\">Best Practices for Collecting User Data Consents<\/a>,&#8221; we talk through some considerations you will want to keep in mind and share examples of how to design and implement an opt-in flow.\u00a0 <\/strong><\/em><\/p>\n<p>Our <a href=\"https:\/\/developer.mozilla.org\/en-US\/Add-ons\/AMO\/Policy\/Reviews#Privacy_and_User_Consent\">review policies for addons.mozilla.org (AMO)<\/a> require transparency when it comes to an add-on&#8217;s features and how they might affect a user&#8217;s privacy and security.<\/p>\n<p>These policies are particularly relevant in cases where an add-on includes monetization features that are unrelated to its main function. For example, a video downloader add-on could include a shopping recommendation feature that injects offers from commercial websites. In cases like this, to be listed on <a href=\"https:\/\/addons.mozilla.org\/\">AMO<\/a> the feature would need to be opt-in. Opt-in means the add-on needs to present to the user the <strong>option to enable<\/strong> the feature, with a <strong>default action of keeping it disabled<\/strong>.<\/p>\n<p>We&#8217;re often asked for examples of add-ons that do this, so I decided to create a sample WebExtension for this purpose. You can find the <a href=\"https:\/\/github.com\/jvillalobos\/opt-in\">code on GitHub<\/a>, and the built and signed example can be <a href=\"http:\/\/xulforge.com\/mozilla\/opt-in.xpi\">downloaded here<\/a>.<\/p>\n<p>The extension implements two opt-in prompts:<\/p>\n<ol>\n<li>A new tab. <img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-7862\" src=\"https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab-600x263.png\" alt=\"Tab opt-in\" width=\"450\" height=\"197\" srcset=\"https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab-600x263.png 600w, https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab-252x110.png 252w, https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab-768x337.png 768w, https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab.png 1077w\" sizes=\"(max-width: 450px) 100vw, 450px\" \/><\/li>\n<li>A panel in the main add-on button. <img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-7861\" src=\"https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/panel.png\" alt=\"Panel opt-in\" width=\"388\" height=\"300\" srcset=\"https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/panel.png 579w, https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/panel-252x195.png 252w\" sizes=\"(max-width: 388px) 100vw, 388px\" \/><\/li>\n<\/ol>\n<p>(If you don&#8217;t recognize the dark theme in the screenshots, it&#8217;s because I&#8217;m using <a href=\"https:\/\/www.mozilla.org\/firefox\/developer\/\">Firefox Developer Edition<\/a>\u2014currently Firefox 49\u2014for testing.)<\/p>\n<p>An add-on would normally implement one prompt or the other. Opening a new tab has the advantage of getting the user&#8217;s attention right away, and has more room for content. The main disadvantage is that it can annoy users and feel too pushy. The pop-up approach is more user-friendly because it appears when the user is ready to engage with the add-on and is better integrated with the add-on UI. However, it wouldn&#8217;t work if the add-on doesn&#8217;t include buttons.<\/p>\n<p>This example is completely minimal, hence the almost complete lack of styling. However, it includes the elements that AMO policies deem necessary:<\/p>\n<ul>\n<li>Text explaining clearly to the user <strong>what the opt-in feature does<\/strong> and why it&#8217;s being offered. In this case, the extra feature is a variation of the <a href=\"https:\/\/github.com\/mdn\/webextensions-examples\/tree\/master\/borderify\">borderify example on GitHub<\/a>.<\/li>\n<li>A link to a <strong>privacy policy<\/strong> and\/or more information about the feature. That page should spell out its privacy and security implications.<\/li>\n<li>A <strong>clear choice between enabling the feature and keeping it disabled<\/strong>, defaulting to disabled. I set <code>autofocus=\"true\"<\/code> to the Cancel button, which can be clearly seen in the popup screenshot.<\/li>\n<\/ul>\n<p>Hitting the Return key in either case, or closing the opt-in tab should be assumed to mean that the user is choosing not to accept the feature (the tab closing case isn&#8217;t implemented in this example to make it easier to test). The example uses the <a href=\"https:\/\/developer.mozilla.org\/en-US\/Add-ons\/WebExtensions\/API\/storage\">storage API<\/a> to keep track of two flags: one that indicates the user has clicked on either button, and one that indicates if the user has enabled the feature or not. After the opt-in is registered as shown, the tab won&#8217;t show up again, and the content changes to something else.<\/p>\n<p><strong>Note:<\/strong> I couldn&#8217;t find a way to look at the extension&#8217;s storage in the developer tools (I suppose it&#8217;s not implemented yet). You can clear the storage to reset the state of the extension by deleting the <code>browser-extension-data<\/code> folder in the profile.<\/p>\n<p>Remember that sneaking in unwanted features is bad for your users and your add-on&#8217;s reputation, so make sure you give your users control and give them clear information to make a decision. Happy coding!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>March 31, 2021 update: The content of this blog post is a little outdated. To learn more about current best practices for creating user opt-ins for extensions, please visit Firefox &hellip; <a class=\"go\" href=\"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/\">Read more<\/a><\/p>\n","protected":false},"author":173,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[44,295],"tags":[580,278873,278876,278879,278871],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Writing an opt-in UI for an extension - Mozilla Add-ons Community Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jorge Villalobos\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/\",\"name\":\"Writing an opt-in UI for an extension - Mozilla Add-ons Community Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab-600x263.png\",\"datePublished\":\"2016-07-15T15:33:58+00:00\",\"dateModified\":\"2021-03-30T21:58:47+00:00\",\"author\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/a098261b4b5510d408ff31f492606925\"},\"breadcrumb\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/#primaryimage\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab.png\",\"contentUrl\":\"https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab.png\",\"width\":1077,\"height\":472,\"caption\":\"Tab opt-in\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blog.mozilla.org\/addons\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Writing an opt-in UI for an extension\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#website\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/\",\"name\":\"Mozilla Add-ons Community Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.mozilla.org\/addons\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/a098261b4b5510d408ff31f492606925\",\"name\":\"Jorge Villalobos\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g\",\"caption\":\"Jorge Villalobos\"},\"description\":\"Jorge is the Product Manager for addons.mozilla.org\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/author\/jvillalobosmozilla-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Writing an opt-in UI for an extension - Mozilla Add-ons Community Blog","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:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/","twitter_misc":{"Written by":"Jorge Villalobos","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/","url":"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/","name":"Writing an opt-in UI for an extension - Mozilla Add-ons Community Blog","isPartOf":{"@id":"https:\/\/blog.mozilla.org\/addons\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/#primaryimage"},"image":{"@id":"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/#primaryimage"},"thumbnailUrl":"https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab-600x263.png","datePublished":"2016-07-15T15:33:58+00:00","dateModified":"2021-03-30T21:58:47+00:00","author":{"@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/a098261b4b5510d408ff31f492606925"},"breadcrumb":{"@id":"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/#primaryimage","url":"https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab.png","contentUrl":"https:\/\/blog.mozilla.org\/addons\/files\/2016\/07\/tab.png","width":1077,"height":472,"caption":"Tab opt-in"},{"@type":"BreadcrumbList","@id":"https:\/\/blog.mozilla.org\/addons\/2016\/07\/15\/writing-an-opt-in-ui-for-an-extension\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog.mozilla.org\/addons\/"},{"@type":"ListItem","position":2,"name":"Writing an opt-in UI for an extension"}]},{"@type":"WebSite","@id":"https:\/\/blog.mozilla.org\/addons\/#website","url":"https:\/\/blog.mozilla.org\/addons\/","name":"Mozilla Add-ons Community Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.mozilla.org\/addons\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/a098261b4b5510d408ff31f492606925","name":"Jorge Villalobos","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g","caption":"Jorge Villalobos"},"description":"Jorge is the Product Manager for addons.mozilla.org","url":"https:\/\/blog.mozilla.org\/addons\/author\/jvillalobosmozilla-com\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts\/7860"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/users\/173"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/comments?post=7860"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts\/7860\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/media?parent=7860"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/categories?post=7860"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/tags?post=7860"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}