{"id":19932722,"url":"https://github.com/mixmaxhq/user-gate","last_synced_at":"2026-02-27T12:46:23.842Z","repository":{"id":10273280,"uuid":"65049654","full_name":"mixmaxhq/user-gate","owner":"mixmaxhq","description":"Server-less feature gates that don't compromise users' privacy.","archived":false,"fork":false,"pushed_at":"2023-11-20T18:41:31.000Z","size":526,"stargazers_count":4,"open_issues_count":2,"forks_count":0,"subscribers_count":19,"default_branch":"master","last_synced_at":"2026-02-15T16:40:06.532Z","etag":null,"topics":["bloom-filter","bloom-filters","corgi-tag","feature-gate"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mixmaxhq.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2016-08-05T21:17:49.000Z","updated_at":"2023-07-12T23:22:10.000Z","dependencies_parsed_at":"2023-11-20T20:01:08.331Z","dependency_job_id":null,"html_url":"https://github.com/mixmaxhq/user-gate","commit_stats":{"total_commits":63,"total_committers":7,"mean_commits":9.0,"dds":0.5396825396825398,"last_synced_commit":"d159e62f9abed1bc7dce14f4b40ae7cdf5c9b507"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/mixmaxhq/user-gate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixmaxhq%2Fuser-gate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixmaxhq%2Fuser-gate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixmaxhq%2Fuser-gate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixmaxhq%2Fuser-gate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mixmaxhq","download_url":"https://codeload.github.com/mixmaxhq/user-gate/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixmaxhq%2Fuser-gate/sbom","scorecard":{"id":650934,"data":{"date":"2025-08-11","repo":{"name":"github.com/mixmaxhq/user-gate","commit":"561595a7c24943d301d750a977a1709b1228be26"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.3,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":4,"reason":"Found 7/17 approved changesets -- score normalized to 4","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 23 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"51 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-6chw-6frg-f759","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw","Warn: Project is vulnerable to: GHSA-w8qv-6jwh-64r5","Warn: Project is vulnerable to: GHSA-wg6g-ppvx-927h","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-vh7m-p724-62c2","Warn: Project is vulnerable to: GHSA-r9p9-mrjm-926w","Warn: Project is vulnerable to: GHSA-434g-2637-qmqr","Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m","Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw","Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p","Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747","Warn: Project is vulnerable to: GHSA-vjh7-7g9h-fjfh","Warn: Project is vulnerable to: GHSA-qrmc-fj45-qfc2","Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3","Warn: Project is vulnerable to: MAL-2023-462","Warn: Project is vulnerable to: GHSA-ww39-953v-wcq6","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-h7cp-r72f-jxh6","Warn: Project is vulnerable to: GHSA-v62p-rq8g-8h59","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-g4rg-993r-mgx7","Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9","Warn: Project is vulnerable to: GHSA-r628-mhmh-qjhw","Warn: Project is vulnerable to: GHSA-9r2w-394v-53qc","Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh","Warn: Project is vulnerable to: GHSA-qq89-hq3f-393p","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-21T13:29:31.145Z","repository_id":10273280,"created_at":"2025-08-21T13:29:31.145Z","updated_at":"2025-08-21T13:29:31.145Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29895642,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T12:09:13.686Z","status":"ssl_error","status_checked_at":"2026-02-27T12:09:13.282Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["bloom-filter","bloom-filters","corgi-tag","feature-gate"],"created_at":"2024-11-12T23:11:21.450Z","updated_at":"2026-02-27T12:46:23.824Z","avatar_url":"https://github.com/mixmaxhq.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# user-gate\n\nThis project lets you define server-less feature gates without compromising\nusers' privacy. It comes in two parts:\n\n* a Node module / CLI tool that let you encode a list of users\n* a browser module that lets you check whether a user is on the list\n\nSince the users are encoded (details [here](#user-encoding-scheme)), you can ship\nthe whole list to the client without exposing your users' information.\n\nThis is useful in scenarios where you can't or don't want to define server logic\nto implement such a feature gate.\n\nAdditional features:\n\n* You can check if the user is on the list from Node too (though this is primarily\nfor the benefit of the CLI tool)\n* You can let a certain proportion i.e. 50% of users through the gate, independent\nof the list, and deterministically (user X will always be allowed through the gate\neven if they reload).\n* v1.x and v2.x of this project offer two different [encoding schemes](#user-encoding-scheme)\nwith different performance tradeoffs.\n\n## Installation\n\n\u003e We recommend installing the latest v2.x release. Some users will prefer v1.x's\ntradeoffs, however. See comparison [here](#comparison-table).\n\nFor encoding the list:\n\n```sh\n# As part of some JS build process:\nnpm install user-gate --save-dev\n\n# Using the CLI tool:\nnpm install user-gate -g\n```\n\nFor checking the list:\n\n```sh\n# From both Node and the browser:\nnpm install user-gate --save\n\n# Using the CLI tool:\nnpm install user-gate -g\n```\n\n## Usage\n\n### Encoding the list\n\nLet's say that you have a list of users like\n\n```js\n// users.json\n[\n  \"jeff@mixmax.com\",\n  \"bob@mixmax.com\"\n]\n```\n\n(These could be any sort of strings, emails or user IDs or whatever.)\n\nYou can encode this list using `user-gate`'s Node API or using the CLI tool. Using the\nNode API:\n\n```js\nvar UserGateEncoder = require('user-gate').encoder;\n\nvar gateEncoder = new UserGateEncoder({\n  users: JSON.parse(fs.readFileSync('users.json', 'utf8')),\n  sample: 0.5\n});\n\n// `JSON.stringify` calls `toJSON` on the encoder.\nfs.writeFileSync('gate.json', JSON.stringify(gateEncoder));\n```\n\nYou can also encode the list as part of a streaming workflow e.g. a\n[Gulp](http://gulpjs.com/) task that publishes the feature gate to Cloudfront:\n\n```js\nvar argv = require('yargs').argv;\nvar awspublish = require('gulp-awspublish');\nvar JSONStream = require('JSONStream');\nvar rename = require('gulp-rename');\nvar UserGateEncoder = require('user-gate').encoder;\n\ngulp.task('updateGate', function() {\n  var publisher = awspublish.create(/* configuration omitted */);\n\n  var gateEncoder = new UserGateEncoder({\n    // We don't specify `users` here because the encoder reads the list from the\n    // JSON stream below.\n    sample: 0.5\n  });\n\n  // For v2.x.\n  var numUsers = argv.numUsers;\n\n  return gulp.src(argv.users)\n    .pipe(JSONStream.parse('*'))\n    .pipe(gateEncoder.toStream({ numUsers }))\n    .pipe(rename('gate.json'))\n    .pipe(publisher.publish());\n})\n```\n\nOr you can encode the list using the CLI tool:\n\n```sh\nuser-gate encode --list users.json --list-size 100 --sample 0.5 gate.json\n```\n\n### Checking the list\n\nIn the browser:\n\nIf your application is capable of importing ES6 modules:\n\n```javascript\nimport UserGate from 'user-gate';\n```\n\nAlternatively,\n\n```html\n\u003c!-- Loads `UserGate` into `window`. There is also a minified version available, `dist/bundle.min.js`.--\u003e\n\u003cscript src=\"node_modules/user-gate/dist/bundle.js\"\u003e\u003c/script\u003e\n\n\u003cscript type=\"text/javascript\"\u003e\n  // Assuming that you have jQuery for the purposes of this example.\n  $.getJSON('gate.json')\n    .then(function(json) {\n      var gate = new UserGate(json);\n\n      var allowed = [\n        gate.allows('jeff@mixmax.com'),\n        gate.allows('walt@mixmax.com'),\n        gate.allows('alice@mixmax.com')\n      ];\n\n      // v2.x\n      // Logs \"[true, false, true]\":\n      // - jeff@mixmax.com was on the list\n      // - walt@mixmax.com was not on the list\n      // - alice@mixmax.com was not on the list, but is in the first half of users.\n      console.log(allowed);\n\n      // In v1.x `UserGate#allows` returns a promise:\n      Promise.all(allowed).then(function(allowedValues) {\n        // Logs \"[true, false, true]\" as above.\n        console.log(allowedValues);\n      })\n    });\n\u003c/script\u003e\n```\n\nYou can also check the list from Node:\n\n```js\nvar gate = new UserGate(JSON.parse(fs.readFileSync('gate.json', 'utf8')));\n\nvar allowed = gate.allows('jeff@mixmax.com');\n\n// v2.x\nconsole.log(allowed); // Logs \"true\"\n\n// v1.x\nallowed.then(function(allowedValue) {\n  console.log(allowedValue); // Logs \"true\"\n})\n```\n\nOr from the CLI tool:\n\n```sh\n# Prints 'Allowed'\nuser-gate check gate.json jeff@mixmax.com\n```\n\n**Note**: v2.x cannot decode gates produced by v1.x.\n\n## Documentation\n\n### UserGateEncoder\n\nAvailable as `require('user-gate').encoder` in Node. Not available in the browser.\n\nSerializes a user gate to a form that can be deserialized and read by\n[`UserGate`](#usergate).\n\n#### new UserGateEncoder(gate, options)\n\nThis is a constructor, and must be called with `new`.\n\n_gate_:\n\n* _list_: An array of strings identifying the users you wish to allow through\n  the gate (emails, user IDs, whatever). You can also [stream these](#usergateencodertostreamoptions)\n  into the encoder (in addition to users specified here, if you like).\n  Defaults to `[]`.\n* _sample_: The proportion of users to allow through the gate independent of the\n  list, as a number between 0 and 1 e.g `0.5`. See [`UserGate#allows`](#usergateallowsuser)\n  for more information on how this is interpreted. Defaults to `0`.\n\nPassing a falsy or empty _gate_ will result in a gate that allows no users through.\n\n_options_:\n\n* _listFalsePositiveRate_ - (**v2.x only**) If _list_ is specified, this controls the rate at which\n  users should be allowed through the gate even if they aren't on the list. `0.01` is the default\n  (1 out of 100 users should be falsely allowed). Specifying a smaller rate will result in a larger\n  encoded gate. 0 is unachievable.\n\n#### UserGateEncoder#toJSON()\n\nReturns the encoded gate as JSON.\n\nThe encoding format should be considered opaque. However, users (if any) will\nbe hashed ([details](#user-encoding-scheme)).\n\n#### UserGateEncoder#toStream(options)\n\nReturns a stream _to which_ you can write users, and _from which_ you can read\nthe JSON stringification of the encoded gate:\n\n```js\nvar fs = require('fs');\nvar JSONStream = require('JSONStream');\nvar UserGateEncoder = require('user-gate').encoder;\n\nfs.createReadStream('users.json')\n  .pipe(JSONStream.parse('*'))\n  .pipe(new UserGateEncoder().toStream({ numUsers: 100 /* v2.x */}))\n  .pipe(fs.createWriteStream('gate.json'));\n```\n\nPass `{ end: true }` if you only want to use the stream to write the gate out\ni.e. you've already configured the users or aren't going to provide any:\n\n```js\nvar fs = require('fs');\nvar UserGateEncoder = require('user-gate').encoder;\n\nvar gateEncoder = new UserGateEncoder({sample: 0.5});\n\ngateEncoder.toStream({end: true})\n  .pipe(fs.createWriteStream('gate.json'));\n```\n\n**In v2.x**, pass `{ numUsers: 100 }` to indicate that you plan to write \u0026#x7e;100\nusers to the stream. Passing a roughly-accurate estimate is crucial to enforcing\nthe desired false positive rate.\n\n### UserGate\n\nAvailable as `require('user-gate')` in Node, or as `window.UserGate` in the browser.\n\nDeserializes a user gate and checks users against the gate.\n\n#### new UserGate(encodedGate, options)\n\nThis is a constructor, and must be called with `new`.\n\n_encodedGate_ is JSON produced by [`UserGateEncoder`](#usergateencoder).\n\n_options_:\n\n* sample: the percentage of users we wish to let in.\n\n#### UserGate#allows(user)\n\nChecks whether _user_ (a string identifier similar to those encoded) is allowed\nthrough the gate, either because:\n\n* they're on the list\n* they're part of the first _sample_ users\n\nSampling is done by hashing the _user_ string and projecting it onto a sample\nspace - this is both deterministic and uniformly random.\n\nChecking against the list requires an exact match. However, sampling is\ncase-insensitive.\n\n**In v2.x and above**, this returns `true` if _user_ is allowed through the gate, `false` otherwise.\n\n**In v1.x**, this returns a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)\nthat resolves to those Boolean values.\n\n### CLI\n\nTo see the CLI tool's options, invoke `user-gate -h`. You can see help for the\ntool's commands by passing `-h` to those too e.g. `user-gate encode -h`.\n\n## User Encoding Scheme\n\nv1.x and v2.x of this project offer two different schemes for encoding the list of\nusers (if one is provided). Skip to the [comparison table](#comparison-table)\nif you like.\n\nv1.x individually hashes each user using the SHA-256 algorithm. v1.x gates can\ncheck if a user is on the list with 100% accuracy, at the cost of very large gates\n(100.3kB gzipped to encode 3k email addresses).\n\nFor this reason, v2.x switches to encoding users using a [Bloom filter](https://en.wikipedia.org/wiki/Bloom_filter), which produces drastically smaller gates (5.4kB gzipped to encode\n3k email addresses) at the cost of a larger library size (9.2kB vs. 1kB, minified\nand gzipped) and the possibility of false positives when checking the list.\n\nWhat this means is that in v2.x [`UserGate#allows`](#usergateallowsuser) may\nreturn `true` for a user that is not on the list. However, it will never return\n`false` for a user that _is_ on the list. (False negatives are not possible.)\n\nThis ensures that everyone you wanted to have access to the feature does, and\na few others get a sneak peek. The authors of this library consider this to be\ntotally fine.\n\nThe false positive rate is tunable. Making the false positive rate smaller will\nincrease the size of the gate. A 0% rate is unachievable (the gate would be\ninfinitely large).\n\nAs a bonus, [`UserGate#allows`](#usergateallowsuser) became synchronous in v2.x.\n\nv2.x cannot decode gates produced by v1.x.\n\n### Comparison table\n\nProperty                                 | v1.x    | v2.x (recommended)\n---------------------------------------- | ------- | ---\nGate size (3k email addresses, gzipped)  | 100.3kB | 5.4kB\nBrowser script size (minified \u0026 gzipped) | 1kB     | 9.2kB\nEncoding time (3k users, 100 iterations) | 29 sec  | 25.1 sec\nFalse positive rate                      | 0%      | \u0026lt; 1%\nSynchronous?                             | No      | Yes\n\n### The Bloom Filter That v2.x Uses\n\nThere are many Bloom filter implementations in JavaScript, but none that seem to\nbe authoritative. This section documents why v2.x uses the one that it does.\n\nA search for [\"JavaScript bloom filter\"](https://www.google.com/url?sa=t\u0026rct=j\u0026q=\u0026esrc=s\u0026source=web\u0026cd=1\u0026cad=rja\u0026uact=8\u0026ved=0ahUKEwjIhszb2czOAhVBLmMKHQY3AeoQFggeMAA\u0026url=https%3A%2F%2Fwww.jasondavies.com%2Fbloomfilter%2F\u0026usg=AFQjCNE7V5_Q_tKRY_kBbR7EIbZksmwbeA\u0026sig2=EGuv2UAPoGm5hdAKNTwW0g)\nreturns (as of 8/18/2016) the [`bloomfilter`](https://github.com/jasondavies/bloomfilter.js)\nlibrary as the #1 result. However that library requires you manually specify the\nnumber of bits to allocate, which is awkward. More problematic, the author says\nthat [the implementation may be flawed](https://github.com/jasondavies/bloomfilter.js/issues/15#issuecomment-123611448).\n\nThe #2 result, the [`bloom-filter`](https://github.com/bitpay/bloom-filter)\nlibrary, remedies these issues. If you tell it how many elements you want to store,\nand the desired false positive rate, it figures out how much memory to allocate.\nIn addition, was developed by a company (Bitpay) to conform to a spec ([Bitcoin\nconnection filtering](https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki))\nwhich gave us confidence in its reliability.\n\nWe use @semaj's fork, specifically its\n[`divergence` branch](https://github.com/bitpay/bloom-filter/compare/master...semaj:divergence),\nbecause it seems to offer [better performance](https://github.com/bitpay/bloom-filter/pull/4) and\neven greater\n[correctness](https://github.com/bitpay/bloom-filter/commit/26fc59c6b8aeec715146314d2ccaee604d5e91b5),\nat the cost of a somewhat larger size when built for the browser, due to its dependency on a\n`Buffer` polyfill. We republished it as `@mixmaxhq/bloom-filter` to avoid `npm`'s problems with\ndependencies pulled in from GitHub.\n\nThe authors of this library are not cryptography experts. If you feel that this\nchoice is incorrect in some way, please [open an issue](https://github.com/mixmaxhq/user-gate/issues/new).\n\n## Contributing\n\nWe welcome pull requests! Please lint your code.\n\n### Running Tests\n\nTo run the Node tests: `npm test`.\n\nTo run the browser tests:\n\n1. `npm run build-test` will build the tests and automatically rebuild them\nif they/the code change.\n2. `npm run open-test` will open and run the tests in the browser. Reload the\npage to re-run the tests.\n\n## Release History\n\n* 2.0.2 Switch to `@mixmaxhq/bloom-filter` - no functional changes\n* 2.0.1 Support strict mode environments\n* 2.0.0 Switch to encoding users using Bloom filters. [More details.](#user-encoding-scheme)\n* 1.0.2 Simplify usage by removing unnecessary warning from README (no code changes).\n* 1.0.1 Smaller browser bundle.\n* 1.0.0 Initial release.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmixmaxhq%2Fuser-gate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmixmaxhq%2Fuser-gate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmixmaxhq%2Fuser-gate/lists"}