{"id":13577751,"url":"https://github.com/cavi-au/Consent-O-Matic","last_synced_at":"2025-04-05T15:31:24.148Z","repository":{"id":37390810,"uuid":"224599511","full_name":"cavi-au/Consent-O-Matic","owner":"cavi-au","description":"Browser extension that automatically fills out cookie popups based on your preferences","archived":false,"fork":false,"pushed_at":"2024-10-11T13:00:58.000Z","size":2221,"stargazers_count":2912,"open_issues_count":106,"forks_count":142,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-04-03T15:18:41.144Z","etag":null,"topics":["browser-extension","consent-management","cookies","gdpr"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cavi-au.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-28T07:57:28.000Z","updated_at":"2025-04-03T13:37:22.000Z","dependencies_parsed_at":"2023-02-14T07:16:32.299Z","dependency_job_id":"dfd19b69-d3cb-411a-b824-7f425198656c","html_url":"https://github.com/cavi-au/Consent-O-Matic","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cavi-au%2FConsent-O-Matic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cavi-au%2FConsent-O-Matic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cavi-au%2FConsent-O-Matic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cavi-au%2FConsent-O-Matic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cavi-au","download_url":"https://codeload.github.com/cavi-au/Consent-O-Matic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247358697,"owners_count":20926271,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser-extension","consent-management","cookies","gdpr"],"created_at":"2024-08-01T15:01:24.047Z","updated_at":"2025-04-05T15:31:24.115Z","avatar_url":"https://github.com/cavi-au.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Web Browser","others","Repository app","GDPR and Data Protection"],"sub_categories":[],"readme":"# Consent-O-Matic\n\n* [Introduction](#introduction)\n    * [Further reading](#further-reading)\n    * [Compatible CMPs](#compatible-cmps)\n    * [Permissions](#permissions)\n* [Installation](#installation)\n* [Extending Consent-O-Matic](#extending-consent-o-matic)\n    * [Basic Structure](#basic-structure)\n        * [Detectors](#detectors)\n        * [Methods](#methods)\n    * [DOM Selection](#dom-selection)\n    * [Actions](#actions)\n        * [Click](#click)\n        * [List](#list)\n        * [Consent](#consent)\n        * [Slide](#slide)\n        * [If Css](#if-css)\n        * [Wait For Css](#wait-for-css)\n        * [For Each](#for-each)\n        * [Wait](#wait)\n        * [Hide](#hide)\n        * [Close](#close)\n    * [Matchers](#matchers)\n        * [Css](#css)\n        * [Checkbox](#checkbox)\n    * [Consent](#consent-1)\n    * [Consent Categories](#consent-categories)\n    * [Full example](#full-example)\n\n# Introduction\n\nYou like websites to respect your right to privacy, and your browser clears cookies when you close it.\nConsequently, you get the same cookie-consent box each and every time you visit the same websites. And you tire of submitting the same information over and over. If only there were a way to automate your way out of this pickle? Lucky for you, Consent-O-Matic exists.\n\nConsent-O-Matic is a browser extension that recognizes a great deal of those CMP (Consent Management Provider) pop-ups that we've all grown to both love and hate. But since you've told it your cookie preferences upon installation, it will autofill those forms for you when it encounters them—and let you know that it did so, with a satisfying little checkmark next to its icon. Nice.\n\nAnd since it's an open project by the Centre for Advanced Visualisation and Interaction (CAVI) at Aarhus University, regular people can contribute by adding new rules, updating old rules, or even adding to the documentation (like these very paragraphs you're reading now, written by someone who just happened to discover the project and wanted to help) to make the extension even easier for others to use.\n\n## Further reading\n\nPaper: [Dark Patterns After the GDPR](https://doi.org/10.1145/3313831.3376321)\n\nPDF: [Dark Patterns After the GDPR](https://arxiv.org/pdf/2001.02479.pdf)\n\nPress: [Virksomheder narrer brugerne til mere dataovervågning (PROSA, March 2020, in Danish)](https://www.prosa.dk/artikel/virksomheder-narrer-brugerne-til-mere-dataovervaagning/)\u003csup\u003e[\\[Internet Archive\\]](https://web.archive.org/web/20200511044414/https://www.prosa.dk/artikel/virksomheder-narrer-brugerne-til-mere-dataovervaagning/)\u003c/sup\u003e\n\n## Compatible CMPs\n\nConsent-O-Matic currently works with these CMPs:\n\n* Autodesk\n* begadi.com\n* chandago\n* consentmanager.net\n* cookiebar\n* cookiebot\n* cookiecontrolcivic\n* cookieinformation\n* cookieLab\n* didomi.io\n* dr.dk\n* DPG Media\n* EvidonBanner\n* EvidonIFrame\n* ez-cookie\n* future\n* ikeaToast\n* lemonde.fr\n* oil\n* onetrust\n* optanon\n* optanon-alternative\n* quantcast\n* quantcast2\n* SFR\n* sharethis\n* sourcepoint\n* sourcepointframe\n* sourcepointpopup\n* springer\n* tealium.com\n* theGuardian\n* trustarcbar\n* trustarcframe\n* umf.dk\n* uniconsent\n* Webedia\n* wordpressgdpr\n\n## Permissions\n\nConsent-O-Matic uses the following set of permissions in the browser when installed:\n* Access to read all pages - It searches each page you visit for consent-related popups that it knows how to handle\n* Information about tab URLs - You can turn the extension on/off on a page-by-page basis by clicking the icon. To check if it is enabled it needs to know the address of the page you are visiting\n* Storage - Your preferences and settings are stored directly in your browser\n\nThe extension only communicates with the net by itself in two situations:\n* When fetching and updating rule lists\n* When you report a website as not working through the extension icon menu\n\n# Installation\n\nWe highly recommend installing directly through the official extension store of your browser:\n* [Chrome](https://chrome.google.com/webstore/detail/consent-o-matic/mdjildafknihdffpkfmmpnpoiajfjnjd) (and other Chromium-based browsers)\n* [Firefox](https://addons.mozilla.org/addon/consent-o-matic/) (Desktop / Mobile)\n* [Safari](https://apps.apple.com/gb/app/consent-o-matic/id1606897889) (MacOS / iOS / iPadOS / visionOS)\n* [Edge](https://microsoftedge.microsoft.com/addons/detail/eflcfflijdiekjkegjghbchoncjhfkda) (Windows / MacOS)\n\n\nInstalling through the official channels will automatically keep you up-to-date with new versions when they are released.\n\n## Installing from Archived Release\nAs an alternative to extension stores you can manually download and extract one of the published versions from the [Releases](https://github.com/cavi-au/Consent-O-Matic/releases) page on Github.\n\u003cbr/\u003eIf you do that you have to use the developer feature of the browser to [Load Unpacked](https://developer.chrome.com/docs/extensions/mv3/getstarted/development-basics/#load-unpacked) (Chrome) or [Load Temporary Addon](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_first_WebExtension#installing) (Firefox) and point it at the manifest.json in the unpacked zip-directory.\n\n## Building from Source\nLastly, if you intend to review or make changes to the code, you can build and install directly from the source code:\n```\ngit clone https://github.com/cavi-au/Consent-O-Matic.git\ncd Consent-O-Matic\nnpm install\n```\nand then run one of ```npm run build-firefox``` or ```npm run build-chromium``` or ```npm run build-safari```\n\nFor Firefox or Chromium you can now proceed as above for installing release archives but point the browser at the `build` folder or a folder where you extracted the zip from build/dist/. Safari requires loading the XCode project to further build an app.\n\nWe do not recommend installing from source.\n\n\n\n\n# Extending Consent-O-Matic\n\nIf your favorite CMP is missing from the current list, feel free to either create a custom list that you can add (click the extension icon in your browser, click \"More add-on settings\", click \"Rule lists\", and enter the URL of your custom list.). If you **really** want to contribute, feel free to create a Pull Request while you're at it.\n\n## Basic Structure\n\nA rule list for Consent-O-Matic is a JSON structure that contains the rules for detecting a CMP (Consent Management Provider), and\ndealing with the CMP popup when it is detected.\n\nEach CMP is a named entry and contains 2 parts, `detectors` and `methods`.\n\n```\n{\n   \"myCMP\": {\n      \"detectors\": [ ... ],\n      \"methods\": [ ... ]\n   },\n   \"anotherCMP\": {\n      \"detectors\": [ ... ],\n      \"methods\": [ ... ]\n   },\n}\n```\n\nIf more than 1 detector is added to a CMP, the CMP counts as detected if any of the detectors trigger.\n\n### Detectors\n\nDetectors are the part that detects if a certain rule set should be applied. Basically, if a detector triggers, the methods will be applied.\n\nDetector structure:\n```\n{\n   \"presentMatcher\": [{ ... }],\n   \"showingMatcher\": [{ ... }]\n}\n```\n\nThe present matcher is used to detect if the CMP is present on the page.\n\nSome CMPs still insert the popup HTML into the DOM even when re-visiting a page where you have already given consent earlier. We only want to handle the consent form if its actually showing on the page. This is what the showing matcher is used for.\n\nBoth the present and showing matcher follow the common structure of [`Matchers`](#matchers).\n\nBoth the present and showing matcher can be multiple matchers, only triggering the detector if all of the matchers (respectively for present and showing) apply.\n\n### Methods\n\nMethods are collections of actions. There are 4 methods supported by Consent-O-Matic. `OPEN_OPTIONS`, `DO_CONSENT`, `SAVE_CONSENT`, `HIDE_CMP`\n\nAll the methods are optional, and, if present, the methods will be run in the order given below when a detector is triggered.\n\n```\nHIDE_CMP\nOPEN_OPTIONS\nHIDE_CMP\nDO_CONSENT\nSAVE_CONSENT\n```\n\nMethods take on the form:\n```\n{\n   \"name\": \" ... \",\n   \"action\": { ... }\n}\n```\n\nwhere the name is one of the 4 supported methods and action is the [action](#actions) to execute.\n\n## DOM Selection\n\nMost actions and matchers have some target that they apply to. For this reason, Consent-O-Matic has a DOM selection mechanism that can easily help with selecting the correct DOM element.\n\n```json\n\"parent\": {\n   \"selector\": \".some.css.selector\",\n   \"textFilter\": \"someTextFilter\",\n   \"styleFilter\": {\n      \"option\": \"someStyleOption\",\n      \"value\": \"someStyleValue\",\n      \"negated\": false\n   },\n   \"displayFilter\": true,\n   \"iframeFilter\": false,\n   \"childFilter\": {}\n},\n\"target\": {\n   \"selector\": \".some.css.selector\",\n   \"textFilter\": \"someTextFilter\",\n   \"styleFilter\": {\n      \"option\": \"someStyleOption\",\n      \"value\": \"someStyleValue\",\n      \"negated\": false\n   },\n   \"displayFilter\": true,\n   \"iframeFilter\": false,\n   \"childFilter\": {}\n}\n```\n\nThere are 2 parts, `parent` and `target`. The `parent` is optional but if it exists it will be resolved first, and used as the starting point for `target`. This allows you to construct very complicated selections of elements that wouldn't otherwise be possible with a single plain CSS selector. One example of such is selecting into shadow DOM - where using parent to target the element with the shadow allows querying its children with the selector.\n\nAll the parameters to `parent` and `target` except `selector` are optional.\n\nThe selection method works by using the css selector from `selector` and then filtering the resulting DOM nodes via the various available filters:\n\n* `textFilter` filters all nodes that do not include the given text. It can also be given as an array `\"textFilter\":[\"filter1\", \"filter2\"]` and then it filters all nodes that do not include one of the given text filters.\n\n* `styleFilter` filters based on computedStyles. `option` is the style option to compare for example `position`, `value` is the value to compare against and `negated` sets if the option value should match or not match the given value.\n\n* `displayFilter` can be used to filter nodes based on if they are display hidden or not.\n\n* `iframeFilter` filters nodes based on if they are inside an iframe or not.\n\n* `childFilter` is a fully new DOM selection, that then filters on the original selection, based on if a selection was made by `childFilter` or not.\n\nHere is an example DOM selection:\n```json\n\"parent\": {\n   \"selector\": \".myParent\",\n   \"iframeFilter\": true,\n   \"childFilter\": {\n      \"target\": {\n         \"selector\": \".myChild\",\n         \"textFilter\": \"Gregor\"\n      }\n   }\n},\n\"target\": {\n   \"selector\": \".myTarget\"\n}\n```\nThis selector first tries to find the `parent` which is a DOM element with the class `myParent` that is inside an iframe and has a child DOM element with the class `myChild` that contains the text \"Gregor\".\n\nThen, using this parent as \"root\", it tries to find a DOM element with the class `myTarget`.\n\nThis could then be the target of an action or matcher.\n\n## Actions\n\nActions are the part of Consent-O-Matic that actually do stuff. Some actions do something to a target selection, others have to do with control flow.\n\n### Click\n\nThis action simulates a mouse click on its target.\n\nExample:\n```json\n{\n   \"type\": \"click\",\n   \"target\": {\n      \"selector\": \".myButton\",\n      \"textFilter\": \"Save settings\"\n   },\n   \"openInTab\": false\n}\n```\n\n`openInTab` if set to true, will trigger a ctrl+shift+click instead of a click, which should make the link, if any, open in a new tab, and focus that tab.\n\nIn this example we only use a simple `target` with a `textFilter` but full [DOM selection](#dom-selection) is supported.\n\n### List\n\nThis action runs a list of actions in order.\n\nExample:\n```json\n{\n   \"type\": \"list\",\n   \"actions\": []\n}\n```\n\n`actions` is an array of actions that will all be run in order.\n\n### Consent\n\nThe consent action takes an array of consents, and tries to apply the users consent selections.\n\nExample:\n```json\n{\n   \"type\": \"consent\",\n   \"consents\": []\n}\n```\n\n`consents` is an array of [Consent](#consent-1) types\n\n### Slide\n\nSome consent forms use a slider to set a consent level, this action supports simulating sliding with such a slider.\n\nExample:\n```json\n{\n   \"type\": \"slide\",\n   \"target\": {\n      \"selector\": \".mySliderKnob\"\n   },\n   \"dragTarget\": {\n      \"target\": {\n         \"selector\": \".myChoosenOption\"\n      }\n   },\n   \"axis\": \"y\"\n}\n```\n\n`target` is the target DOM element to simulate the slide motion on.\n\n`dragTarget` is the DOM element to use for slide distance.\n\n`axis` selects if the slider should go horizontal \"x\" or vertical \"y\".\n\nThe slide event will simulate that the mouse dragged `target` the distance from `target` to `dragTarget` on the given `axis`.\n\n### If Css\n\nThis action is used as control flow, running another action depending on if a DOM selection finds an element or not.\n\nExample:\n```json\n{\n   \"type\": \"ifcss\",\n   \"target\": {\n      \"selector\": \"\",\n   },\n   \"trueAction\": {\n      \"type\": \"click\",\n      \"target\": {\n         \"selector\": \".myTrueButton\"\n      }\n   },\n   \"falseAction\": {\n      \"type\": \"click\",\n      \"target\": {\n         \"selector\": \".myFalseButton\"\n      }\n   }\n}\n```\n\n`trueAction` is an action that will be run if the DOM selection finds an element.\n`falseAction` will be run when the DOM selection does not find an element.\n\n### Wait For Css\n\nThis action waits until the DOM selector finds a DOM element that matches. This is mostly used if something in the consent form loads slowly and needs to be waited for.\n\nExample:\n```json\n{\n   \"type\": \"waitcss\",\n   \"target\": {\n      \"selector\": \".myWaitTarget\"\n   },\n   \"retries\": 10,\n   \"waitTime\": 200,\n   \"negated\": false\n}\n```\n\n`retries` is the number of times to check for the target DOM element. Deafults to 10.\n\n`waitTime` determines the time between retry attempts. Defaults to 250.\n\n`negated` makes wait for css wait until the target is NOT found.\n\n### For Each\n\nIf some set of actions needs to be run several times, but with different DOM nodes as root, the for each action can be used. It runs its action 1 time for each DOM element that is selected by its DOM selection; all actions run inside the for each loop will see the DOM as starting from the currently selected node.\n\nExample:\n```json\n{\n   \"type\": \"foreach\",\n   \"target\": {\n      \"selector\": \".loopElement\"\n   },\n   \"action\": {}\n}\n```\n\n`action` is the action to run for each found DOM element.\n\n### Wait\n\nThis action waits the given amount of milliseconds before continuing.\n\nExample:\n```json\n{\n   \"type\": \"wait\",\n   \"waitTime\": 250\n}\n```\n\n### Hide\n\nThis action sets css class 'ConsentOMatic-CMP-Hider' on the DOM selection. The default css rules will then set opacity to 0 on the element.\n\nExample:\n```json\n{\n   \"type\": \"hide\",\n   \"target\": {\n      \"selector\": \".myHiddenClass\"\n   }\n}\n```\n\n### Close\n\nThis action closes the current tab, useful for consent providers like Evidon, which likes to open new tabs with the consent dashboard inside.\n\nExample:\n```json\n{\n   \"type\": \"close\"\n}\n```\n\n## Matchers\n\nMatchers are used to check for the presence of some DOM selection, or the state of some DOM selection.\n\n### Css\n\nThis matcher checks for the presence of a DOM selection, and return that it matches if it exists.\n\nExample:\n```json\n{\n   \"type\": \"css\",\n   \"target\": {\n      \"selector\": \".myMatchingClass\"\n   }\n}\n```\n\n### Checkbox\n\nThis matcher checks the state of an `\u003cinput type='checkbox' /\u003e` and returns that it matches if the checkbox is checked.\n\nExample:\n```json\n{\n   \"type\": \"checkbox\",\n   \"target\": {\n      \"selector\": \".myInputCheckbox\"\n   }\n}\n```\n\n## Consent\n\nThis is what is used inside [Consent Actions](#consent) and defines the actual consent that the user should be giving or not giving.\n\nEach consent has a type, that matches the consent categories inside Consent-O-Matic, so if a user has toggled the first consent category to ON, (Type A) and the consent is of type \"A\", then the consent will be enabled.\n\nUsually the consent is given either as a toggle, or a set of buttons on/off. Therefore `consent` has a mechanism for each of these cases.\n\nExample:\n```json\n{\n   \"type\": \"A\",\n   \"toggleAction\": {},\n   \"matcher\": {},\n   \"trueAction\": {},\n   \"falseAction\": {}\n}\n```\n\n`type` is the type of consent category this rule defines and determines if this consent should be on or off depending on the user's selection for that type of category.\n\n`toggleAction` this action is used to select consent if the popup uses a toggle or a switch to communicate consent. The action will be run if the matcher says the consent is in a state different from what the user has asked it to be, otherwise it will not be run.\n\n`matcher` is the matcher used to check which state the consent is in. For a [checkbox matcher](#checkbox), the consent is given if the checkbox is checked. For a [css matcher](#css) the consent is given if the matcher finds a DOM selection.\n\n`trueAction` and `falseAction` are actions used if consent instead has to be given by pressing one of two buttons, rather than being toggled on/off. These will be run depending on the user's selection of consent. If the user has given consent for this category type, the `trueAction` will be run, and `falseAction` will be run if the user has not given consent to this category type.\n\nIf `toggleAction` and `matcher` is present on the content config, toggleAction will be used, if one of them is missing, `trueAction`/`falseAction` will be used instead.\n\n### Consent Categories\n\nAs seen in the addon settings, in the same order:\n\n* D: Information Storage and Access\n* A: Preferences and Functionality\n* B: Performance and Analytics\n* E: Content selection, delivery, and reporting\n* F: Ad selection, delivery, and reporting\n* X: Other Purposes\n\n## Full example\n\nPutting it all together, here is a full example of a CMP \"myCMP\" that has 2 consent categories to toggle.\n\n```json\n{\n   \"myCMP\": {\n      \"detectors\": [\n         {\n            \"presentMatcher\": {\n               \"type\": \"css\",\n               \"target\": {\n                  \"selector\": \"#theCMP\"\n               }\n            },\n            \"showingMatcher\": {\n               \"target\": {\n                  \"selector\": \"#theCMP.isShowing\"\n               }\n            }\n         }\n      ],\n      \"methods\": [\n         {\n            \"name\": \"OPEN_OPTIONS\",\n            \"action\": {\n               \"type\": \"click\",\n               \"target\": {\n                  \"selector\": \".button\",\n                  \"textFilter\": \"Change settings\"\n               }\n            }\n         },\n         {\n            \"name\": \"DO_CONSENT\",\n            \"action\": {\n               \"type\": \"list\",\n               \"actions\": [\n                  {\n                     \"type\": \"click\",\n                     \"target\": {\n                        \"selector\": \".menu-vendors\"\n                     }\n                  },\n                  {\n                     \"type\": \"consent\",\n                     \"consents\": [\n                        {\n                           \"type\": \"A\",\n                           \"matcher\": {\n                              \"type\": \"checkbox\",\n                              \"parent\": {\n                                 \"selector\": \".vendor-item\",\n                                 \"textFilter\": \"Functional cookies\"\n                              },\n                              \"target\": {\n                                 \"selector\": \"input\"\n                              }\n                           },\n                           \"toggleAction\": {\n                              \"type\": \"click\",\n                              \"parent\": {\n                                 \"selector\": \".vendor-item\",\n                                 \"textFilter\": \"Functional cookies\"\n                              },\n                              \"target\": {\n                                 \"selector\": \"label\"\n                              }\n                           }\n                        },\n                        {\n                           \"type\": \"F\",\n                           \"matcher\": {\n                              \"type\": \"checkbox\",\n                              \"parent\": {\n                                 \"selector\": \".vendor-item\",\n                                 \"textFilter\": \"Advertisement cookies\"\n                              },\n                              \"target\": {\n                                 \"selector\": \"input\"\n                              }\n                           },\n                           \"toggleAction\": {\n                              \"type\": \"click\",\n                              \"parent\": {\n                                 \"selector\": \".vendor-item\",\n                                 \"textFilter\": \"Advertisement cookies\"\n                              },\n                              \"target\": {\n                                 \"selector\": \"label\"\n                              }\n                           }\n                        }\n                     ]\n                  }\n               ]\n            }\n         },\n         {\n            \"name\": \"SAVE_CONSENT\",\n            \"action\": {\n               \"type\": \"click\",\n               \"target\": {\n                  \"selector\": \".save-consent-btn\"\n               }\n            }\n         }\n      ]\n   }\n}\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcavi-au%2FConsent-O-Matic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcavi-au%2FConsent-O-Matic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcavi-au%2FConsent-O-Matic/lists"}