{"id":38613493,"url":"https://github.com/cabify/prom-react","last_synced_at":"2026-01-17T08:47:46.344Z","repository":{"id":36963659,"uuid":"424909358","full_name":"cabify/prom-react","owner":"cabify","description":"Add Prometheus metrics to your React App. Built on top of promjs and react-performance libraries [managed by soy-programador]","archived":false,"fork":false,"pushed_at":"2025-11-28T16:45:20.000Z","size":2230,"stargazers_count":38,"open_issues_count":2,"forks_count":4,"subscribers_count":43,"default_branch":"main","last_synced_at":"2025-11-30T21:59:01.614Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cabify.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-11-05T10:29:52.000Z","updated_at":"2025-11-28T16:44:34.000Z","dependencies_parsed_at":"2023-09-23T12:39:41.427Z","dependency_job_id":"d47742d0-83bf-44b2-9764-36d6d62436e9","html_url":"https://github.com/cabify/prom-react","commit_stats":{"total_commits":327,"total_committers":10,"mean_commits":32.7,"dds":0.2262996941896025,"last_synced_commit":"d68e357b87c4ffc8a5c393950de11a8bcf4015d1"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/cabify/prom-react","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cabify%2Fprom-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cabify%2Fprom-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cabify%2Fprom-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cabify%2Fprom-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cabify","download_url":"https://codeload.github.com/cabify/prom-react/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cabify%2Fprom-react/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28504495,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T06:57:29.758Z","status":"ssl_error","status_checked_at":"2026-01-17T06:56:03.931Z","response_time":85,"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":[],"created_at":"2026-01-17T08:47:46.276Z","updated_at":"2026-01-17T08:47:46.337Z","avatar_url":"https://github.com/cabify.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## prom-react\n\n\u003c!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --\u003e\n\n[![All Contributors](https://img.shields.io/badge/all_contributors-11-orange.svg?style=flat-square)](#contributors-)\n\n\u003c!-- ALL-CONTRIBUTORS-BADGE:END --\u003e\n\nAdd Prometheus metrics to your React App. Built on top of promjs and react-performance libraries\n\n### Scope and purpose\n\nThe main objective of this package is to provide production runtime observability to React frontends,\nallowing to monitor and alert about operational metrics such as, but not limited to, section loading times, load app errors and so.\n\nTo do so, this library offers a `MetricsProvider` that is built on top of [promjs](https://www.npmjs.com/package/promjs)\nand [@shopify/react-performance](https://www.npmjs.com/package/@shopify/react-performance). With a minimal\ninstrumentation of your code, you can create fancy Grafana dashboards or raise prometheus alerts of your frontend app.\n\nTo better understand the purpose and architectural decisions behind this library, please take a look into\n[this article / presentation](https://www.weave.works/blog/browser-metrics-into-prometheus/)\n\nIt is important to notice that, taking into account Prometheus pull model, this library needs to push metrics\ninto some Prometheus aggregation gateway to make them available. It is recommended to use against a\n[prom-aggregation-gateway](https://github.com/weaveworks/prom-aggregation-gateway) instance, but\nother alternatives might work as well.\n\n### Installation\n\n```sh\n$ yarn add @cabify/prom-react\n```\n\n### Usage\n\n#### Basic usage\n\nFirst, you'll need to add a `MetricsProvider` into your app. It is desirable to add it to the root of\nyour app, to make it widely available.\n\n```tsx\n// src/index.tsx\nimport { MetricsProvider } from '@cabify/prom-react';\n\nconst normalizePath = (path: string) =\u003e {\n  const match = path.match(/\\/products\\/(\\d+)/);\n  if (match) {\n    return `/products/:id`;\n  }\n  return path;\n};\n\nconst AppRoot = () =\u003e (\n  \u003cMetricsProvider appName=\"my-app-name\" owner=\"my-team\" getNormalizedPath={normalizePath} metricsAggregatorUrl=\"https://some-metrics-aggregator.com/push-metrics\"\u003e\n    \u003cOtherProviders\u003e\n      \u003cApp /\u003e\n    \u003c/OtherProviders\u003e\n  \u003c/MetricsProvider\u003e\n);\n\nrender(\u003cAppRoot /\u003e, document.getElementById('app'));\n```\n\nAfter that, in all your app pages or section root components, you need to add a navigation mark.\nIt is important to notice that all your page component should add `usePerformanceMark`. If there is a single page that doesn't\nexplicitly call `usePerformanceMark(Stage.Complete, 'page-id')`, your metric values will show incorrect results.\nYou will notice it for unusual high values for `prom_react_navigation_seconds` (it will affect to your p99 metrics).\nSee [@shopify/react-performance](https://www.npmjs.com/package/@shopify/react-performance#track-some-stats)\nfor more info.\n\n```tsx\n// src/pages/Products.tsx\nimport { usePerformanceMark, Stage } from '@cabify/prom-react'; // handy re-export of @shopify/react-performance utils\n\nexport const Products = () =\u003e {\n  // whatever way to load the page data\n  const [products, isLoading] = useFetchProducts();\n\n  usePerformanceMark(isLoading ? Stage.Usable : Stage.Complete, 'products');\n\n  return '...';\n};\n```\n\nIf you want also to monitor your app load failures (missing bundle files, js errors at boot time, etc), you'll\nneed to add the following small snippet to your `index.html` file (it must be placed there so it will execute\neven if your bundle is unreachable / not working):\n\n```js\nwindow.__PROM_REACT_LOAD_FAILURE_TIMEOUT__ = setTimeout(function () {\n  var xhr = new XMLHttpRequest();\n  var str = '# HELP prom_react_app_loaded Application loaded counter\\n';\n  str += '# TYPE prom_react_app_loaded counter\\n';\n  str += 'prom_react_app_loaded{app_name=\"\u003c\u003cAPP_NAME\u003e\u003e\",status=\"failure\"} 1\\n';\n\n  xhr.open('POST', '\u003c\u003cMETRICS_AGGREGATOR_URL\u003e\u003e');\n  xhr.setRequestHeader('Content-Type', 'text/plain');\n  xhr.send(str);\n}, 3000);\n```\n\n(Please remember to replace `\u003c\u003cMETRICS_AGGREGATOR_URL\u003e\u003e` and `\u003c\u003cAPP_NAME\u003e\u003e` placeholders to match your configuration)\n\nAdding such instrumentation will provide these golden metrics out of the box:\n\n- `prom_react_app_loaded`: Application loaded counter. It will observe both succesful / failure loads.\n- `prom_react_app_unloaded`: Application unloaded counter. Uses `navigator.sendBeacon` API behind the scenes.\n- `prom_react_performance_seconds`: Histogram to store load performance event timings (`dcl`, `ttfb`, `ttfp`, etc.).\n- `prom_react_navigation_duration_seconds`: Histogram to store navigation times between sections.\n  It includes both full page loads (`navigation_type=\"full_page`) and in-app navigations via\n  history `pushState` or react-router (`navigation_type=\"in_app`). It also includes a label\n  with the `path` (you need to take care about [cardinality explosion](https://blog.freshtracks.io/bomb-squad-automatic-detection-and-suppression-of-prometheus-cardinality-explosions-62ca8e02fa32)\n  by using [getNormalizedPath](#metricsprovider) prop when creating `MetricsProvider`)\n- `prom_react_ttc_seconds`: Histogram to store page TimeToComplete navigation times.\n  It includes same labels as `navigation_duration_seconds` metric.\n- `prom_react_ttu_seconds`: Histogram to store page TimeToUsable navigation times.\n  It includes same labels as `navigation_duration_seconds` metric.\n\n#### Adding custom metrics\n\nYou can add your custom app metrics to use them when needed. To do so, just attach them to `MetricsProvider`.\nLater on, you can take advantage of `useMetrics` hook to add observations on those metrics:\n\n```tsx\n// src/index.tsx\n\nimport { MetricsProvider } from '@cabify/prom-react';\n\n// please remember to define them outside the component to avoid unneeded re-renders\nconst customMetrics: MetricDefinition[] = [\n  {\n    type: 'counter',\n    name: 'my_app_report_download_count',\n    description: 'Number of reports downloaded',\n  },\n];\n\nconst MyApp = () =\u003e {\n  return (\n    \u003cMetricsProvider appName=\"MyApp\" customMetrics={customMetrics}\u003e\n      ...\n    \u003c/MetricsProvider\u003e\n  );\n};\n\n// Any inner component\nimport { useMetrics } from '@cabify/prom-react';\n\nconst ReportsDownloadButton = () =\u003e {\n  const { observe } = useMetrics();\n\n  const downloadReport = () =\u003e {\n    observe('my_app_report_download_count', { custom_tag: 'custom value' }, 1);\n\n    // your app code\n  };\n\n  return \u003cdiv onClick={downloadReport}\u003eDownload report\u003c/div\u003e;\n};\n```\n\n### API\n\n#### MetricsProvider\n\nReact component that configures all the monitoring infrastructure and add the aforementioned\ngolden metrics. It must be placed in the root of your component tree.\n\nProps:\n\n- `appName: string;`: Name of the app. All metrics will include a label 'app_name'\n  with this value.\n- `owner?: string;`: Owner of the app. All metrics will include a label 'owner' with this value.\n- `metricsAggregatorUrl?: string;`: Url of the push gateway aggregator.\n  If not set, metrics will be collected but not sent.\n- `customMetrics?: MetricDefinition[];`: Custom application metrics. Please define in a const\n  outside the component to avoid infinite loops trying to create them.\n- `fetchOptions?: Partial\u003cRequestInit\u003e`: Extra fetch options (headers, credentials, etc) to be used when sending metrics to the aggregator.\n- `getNormalizedPath?: (path: string) =\u003e string;`: Given that all route change metrics include\n  a 'path' label, you should add this function to avoid cardinality issues if you have\n  parameterized routes (ex: `/products/:id`). See [recipes](#recipes) section for examples.\n- `histogramBuckets?: number[]`: Bucket list for the histogram metrics.\n  Defaulted to `[0.01, 0.1, 1, 2, 3, 4, 5, 7, 10, 15]`.\n\n#### usePerformanceMark, Stage, etc.\n\nThis library re-exports all `@shopify/react-performance` to avoid explicitly add it\nto your package dependencies. You can have a look at its\n[API documentation](https://www.npmjs.com/package/@shopify/react-performance#api) for further details.\n\n#### MetricsLogger\n\nReact component that will log into console all metric observations. It won't render anything in the screen.\nYou should not add this in production.\n\nProps:\n\n- `logger?: ObserveCallback`: If set, it will replace the original logger. Ensure the reference of this value doesn't change between renders by memoizing the logger function or defining it outside the component to avoid performance issues.\n\n#### MetricsDebugOverlay\n\nReact component to show metrics debug info. Must be placed under `MetricsProvider`. It shows a not-so-fancy\noverlay with navigation info. It is useful to check if all your sections are properly instrumented with `usePerformanceMark`.\nIt can also log all your observations to console (uses `MetricsLogger` under the hood). You should not show this in production.\n\nProps:\n\n- `onClose?: () =\u003e void`: If set, it will show a close button which will call this callback when pressed\n- `withLogger?: boolean`: If set to true, it will include a `MetricsLogger`. This way, you can have\n  all debugging facilities at hand by only adding this component.\n\n![MetricsDebugOverlay component](./images/MetricsDebugOverlay.png?raw=true 'MetricsDebugOverlay')\n\nNote that these debug components are very basic and may not fit your needs. However, as all metric data\nis available through `useMetrics` hook, you can build your own logger, debugging panel, etc. within\nyour application or as an external library.\n\n#### useMetrics()\n\nHook to access metrics registry and some other ready-to-use helpers. It returns an object\nwith the following properties:\n\n- `observe(metricName, tags?, value?, skipSending?)`:\n  Helper to add an observation to an existing metric. Note that the metric should be created in the provider. It supports both histogram and counter metrics.\n  - `metricName: string`: Name of the metric to add observation to.\n  - `tags?: Record\u003cstring, string\u003e`: Optional tags to add to the observation. All observations added with this method\n    will have `app_name` and `owner` labels properly set.\n  - `value?: number`: Value to add to the observation. It is mandatory for histogram metrics and optional\n    for counter metrics. If not set, this method will increase the counter by `1`.\n  - `skipSending?: boolean`: If set to true, the observation will not be sent to the backend\n    (you can call `sendMetrics()` manually to send observations).\n- `isReady: boolean`: flag to indicate when metrics are ready to be used. You should only rely on\n  this flag if you are planning to add observations to custom metrics when first rendering the app.\n  The rule of thumb here is: only use it if your metric observation raise a warning of \"this metric does not exist\".\n- `sendMetrics: () =\u003e void`: Send metrics to the server. Note: by default, this method is called\n  automatically by `observe`, but you can call it manually if you skip automatic metric send.\n- `histogramBuckets: number[];`: Buckets for histograms configured in the provider. Included here\n  only for testing purposes, it won't be usually needed.\n- `navigationData: NavigationData | null`: Last navigation data.\n- `addObserveListener: (callback: ObserveCallback) =\u003e void;`: Add a listener called whenever an observation is added to the registry.\n- `removeObserveListener: (callback: ObserveCallback) =\u003e void;`: Remove observe listener\n- `registry: Registry`: promjs regisry instance. You should not use this directly,\n  but use `observe` instead. It is exposed for some extremely rare cases and testing purposes.\n\n### Recipes\n\n#### Debugging\n\nIf you want to check if your metrics are being generated properly, you can add the `MetricsLogger` into your\ncomponent tree and all metric observations will be shown in the console.\n\n```tsx\nconst AppRoot = () =\u003e (\n  \u003cMetricsProvider appName=\"my-app-name\" owner=\"my-team\" getNormalizedPath={normalizePath} metricsAggregatorUrl=\"https://some-metrics-aggregator.com/push-metrics\"\u003e\n    \u003cMetricsLogger /\u003e\n    \u003cMyApp /\u003e\n  \u003c/MetricsProvider\u003e\n);\n```\n\nThis will produce log entries like this:\n\n`[prom_react] prom_react_navigation_duration_seconds 1.2456 {app_name: 'my_app', path: '/app', navigation_type: 'full_page' }`\n\nYou can customize the output for `MetricsLogger` by replacing the original loader:\n\n```tsx\nconst metricsLogger = ({ metricName, value, tags }) =\u003e {\n  console.debug('Custom log for prom-react!', metricName, value, tags);\n};\nconst AppRoot = () =\u003e (\n  \u003cMetricsProvider appName=\"my-app-name\" owner=\"my-team\" getNormalizedPath={normalizePath} metricsAggregatorUrl=\"https://some-metrics-aggregator.com/push-metrics\"\u003e\n    \u003cMetricsLogger logger={metricsLogger} /\u003e\n    \u003cMyApp /\u003e\n  \u003c/MetricsProvider\u003e\n);\n```\n\nMoreover, you can also add a widget that will show last navigation event being triggered. This is particularly useful to check\nif all your pages are properly instrumented (you should navigate across your app and the widget should show the right path after\nevery section change).\n\n```tsx\nconst AppRoot = () =\u003e (\n  \u003cMetricsProvider appName=\"my-app-name\" owner=\"my-team\" getNormalizedPath={normalizePath} metricsAggregatorUrl=\"https://some-metrics-aggregator.com/push-metrics\"\u003e\n    {process.env.NODE_ENV !== 'production' \u0026\u0026 \u003cMetricsDebugOverlay withLogger onClose={closeOverlay} /\u003e}\n    \u003cMyApp /\u003e\n  \u003c/MetricsProvider\u003e\n);\n```\n\n#### Configure your grafana dashboards and prometheus alerts\n\n- Average active sessions in a given time range:\n\n```\nincrease(prom_react_app_loaded{app_name=\"$job\", status=\"success\"}[$__range]) -\non() increase(prom_react_app_unloaded{app_name=\"$job\"}[$__range])\n```\n\n- Load app error rate:\n\n```\nrate(prom_react_app_loaded{app_name=\"$job\",status=\"failure\"}[$__rate_interval]) /\nrate(prom_react_app_loaded{app_name=\"$job\"}[$__rate_interval])\n```\n\n- Nth quantile of full page load duration in seconds:\n\n```\nhistogram_quantile($quantile,\nsum(sum(rate(prom_react_navigation_duration_seconds_bucket{app_name=\"$job\",navigation_type=\"full_page\"}[$__rate_interval])\n)\nby (le, path)) without(path))\n```\n\n- Page RPS by path:\n\n```\nsum by (path)(rate(prom_react_navigation_duration_seconds_count{app_name=\"$job\"}[$__rate_interval]) != 0)\n```\n\n- (Prometheus alert). Application load failed:\n\n```\nALERT AppLoadFailed\n  IF     rate(prom_react_app_loaded{app_name=\"my-app\",status=\"failure\"}[5m]) /\n         rate(prom_react_app_loaded{app_name=\"my-app\"}[5m]) \u003e 0.1\n  FOR    15m\n  LABELS {...}\n  ANNOTATIONS {...}\n```\n\n#### getNormalizedPath with routes object\n\nIf you have your routes defined in a global object like (that you later use\nin your react router configuration, for instance):\n\n```ts\nconst Urls = {\n  INDEX: '/app',\n  PRODUCTS: '/app/products',\n  PRODUCT_DETAIL: 'app/product/:id',\n  ...\n}\n```\n\nYou can easily create a `getNormalizedPath` function by:\n\n```ts\nimport { pathToRegexp } from 'path-to-regexp';\n\nconst urlRegExps = Object.values(Urls).map((url) =\u003e ({\n  regExp: pathToRegexp(url),\n  url,\n}));\n\nexport const getNormalizedPath = (url: string) =\u003e {\n  return urlRegExps.find(({ regExp }) =\u003e regExp.test(url))?.url || url;\n};\n```\n\n#### Add authorization header to gateway requests\n\n```tsx\n// src/index.tsx\nimport { MetricsProvider } from '@cabify/prom-react';\n\nconst gatewayFetchOptions = {\n  headers: {\n    Authorization: `Basic ${btoa('login:password')}`,\n  },\n};\n\nconst AppRoot = () =\u003e (\n  \u003cMetricsProvider appName=\"my-app-name\" owner=\"my-team\" fetchOptions={gatewayFetchOptions} metricsAggregatorUrl=\"https://some-metrics-aggregator.com/push-metrics\"\u003e\n    \u003cApp /\u003e\n  \u003c/MetricsProvider\u003e\n);\n```\n\n#### Automatically check that all your pages include navigation marks\n\nIf you can identify your pages root components easily by their file name (for instance if they\nare always named `\u003cSectionName\u003ePage.tsx`), it is easy to add a simple shell script to automatically\ncheck that all of them are properly instrumented. This way you can avoid wrong navigation metric values\n(you can also add such script to your CI pipelines or pre-commit scripts just to make sure an instrumented\ncode doesn't reach production). As an extra tip, if there are files that match your page name structure\nbut are not pages (or the page is instrumented somewhere else), you can add an ignore coment _à la eslint_\n(ex. `// prom-react-ignore`).\n\n```sh\necho \"Checking if all pages are using 'usePerformanceMark'\"\n\nOUTPUT=$(grep --include='*Page.tsx' -Lr 'usePerformanceMark\\|prom-react-ignore' .)\n\nif [ -z \"$OUTPUT\" ]; then\n    echo \"Everything ok\"\nelse\n    echo \"There are pages that are not using 'usePerformanceMark'\"\n    echo \"$OUTPUT\"\n    echo \"Please start using 'usePerformanceMark' on them or add // prom-react-ignore to ignore that file\"\n    exit 1\nfi\n```\n\n### Contributing\n\n- Running tests and linting: `yarn test`\n- Build project: `yarn build`\n\n#### Publish a new version\n\n- Update [CHANGELOG](./CHANGELOG.md) with new features, breaking changes, etc\n- Check you're in `main` branch and everything is up-to-date.\n- Run `yarn publish:\u003cmajor|minor|patch\u003e` or `yarn publish:canary` for canary versions.\n- Run `git push \u0026\u0026 git push --tags`\n- Check all test actions triggered after previous push are ✔️.\n- Go to [create a new release](https://github.com/cabify/prom-react/releases/new), select previously pushed tag and write a Title.\n- Check the action for publish the npm has finished with success.\n- [Check on npm package webpage](https://www.npmjs.com/package/@cabify/prom-react), the version has been published successfully under `latest` tag.\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/jalopez\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/259623?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJavier López\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=jalopez\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/alejandrofdiaz\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/9197247?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlejandro\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=alejandrofdiaz\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://valya.codes/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/7880641?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eValentin Berlin\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=valenber\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/alexgallardo\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/7766614?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlejandro Gallardo Escobar\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=alexgallardo\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/christiandebarrio\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/13832650?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eChristian\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=christiandebarrio\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/riboher\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/11684090?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eRicardo Boluda\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=riboher\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/pablomarquezcabify\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/99354964?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePablo Márquez\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=pablomarquezcabify\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://leireriel.github.io/leire-rico-portfolio/#/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/48056077?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eLeire Rico\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=leireriel\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://www.siete3.com/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/2030605?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eRodrigo\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=area73\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/AlexTemina\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/14157093?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlex Temina\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=AlexTemina\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/fernandezAmor\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/6586552?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003efernandezAmor\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cabify/prom-react/commits?author=fernandezAmor\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcabify%2Fprom-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcabify%2Fprom-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcabify%2Fprom-react/lists"}