Open-source project
GoogleChromeLabs/react-adaptive-hooks avatar
GoogleChromeLabs/react-adaptive-hooks

react-adaptive-hooks: device and network aware React hooks from GoogleChromeLabs

Deliver experiences best suited to a user's device and network constraints

5,154 stars112 forksJavaScriptApache-2.0

At a glance

What is it?
react-adaptive-hooks is a small suite of React hooks that expose network type, Data Saver, memory, CPU core count and media decoding capability to components. It is for teams that want to ship a lighter experience to low-end devices, and it comes with real caveats around browser support and SSR.
Who is it for?
Adopt react-adaptive-hooks if you already render React on the client and want a single place to branch on effective connection type, Data Saver, device memory or logical CPU cores. Do not adopt it if you need guaranteed values in every browser: the README itself notes that the network, Data Saver and memory hooks accept an initial value precisely because the underlying APIs may be missing, and the package is marked experimental.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 151 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • GoogleChromeLabs/react-adaptive-hooks5,154 ★ · -2
Star history
Repository2026-09-232026-11-14
GoogleChromeLabs/react-adaptive-hooks5.2k5.2k

-2 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The problem react-adaptive-hooks solves, and who it is for

Most React apps ship one experience to every device. A phone on slow-2g and a desktop on a fast connection get the same image, the same video, the same bundle. The README states the objective plainly: "Make it easier to target low-end devices while progressively adding high-end-only features on top." That is the whole pitch, and it is a narrow one. This is a library for teams that already have a React component tree and want to branch inside it on signals the browser already exposes, rather than building a separate low-end build or a server-rendered variant per device class. The hooks cover five signals: effective connection type, Data Saver preference, device memory, logical CPU cores, and media decoding capability. It is not a bundler plugin, not a performance monitor, and not a data-fetching library. It hands you values and lets you decide what to render. If you want the framework to make the decision for you, this is the wrong shape of tool.

How the hooks read the browser and what they return

The repository is organized as one directory per concern: network/, save-data/, hardware-concurrency/, memory/ and media-capabilities/, with index.js as the source entry and microbundle producing dist/index.js, dist/index.module.js and dist/index.umd.js. Each hook wraps a browser API and returns a small object. useNetworkStatus returns effectiveConnectionType, whose documented values are slow-2g, 2g, 3g and 4g. useSaveData returns a boolean saveData. useHardwareConcurrency returns numberOfLogicalProcessors. useMemoryStatus returns deviceMemory, "the approximate amount of device memory in gigabytes." useMediaCapabilitiesDecodingInfo checks whether a given content type can be played, which the README illustrates with the Safari and WebM case: Safari does not support WebM, so you fall back to MP4. The important structural detail is the initial-value argument. useNetworkStatus takes an optional initialEffectiveConnectionType string, useSaveData takes initialSaveData, and useMemoryStatus takes an initialMemoryStatus object such as { deviceMemory: 4 }. The README says these exist for browsers that lack the relevant API and for server-side rendering, where you can pass an ECT Client Hint, a Save-Data Client Hint converted to a boolean, or a Device-Memory Client Hint. That is the real architecture: the hook reads the client API when it exists, and you supply the fallback when it does not.

Installing react-adaptive-hooks and a first adaptive image

The README gives two install commands, one for npm and one for yarn. Either produces the same package.

bash
npm i react-adaptive-hooks --save

or:

bash
yarn add react-adaptive-hooks

Hooks are imported from subpaths rather than the package root, so a component that only needs network status pulls in only that module. The README shows the full set of import paths in one block:

js
import { useNetworkStatus } from 'react-adaptive-hooks/network';
import { useSaveData } from 'react-adaptive-hooks/save-data';
import { useHardwareConcurrency } from 'react-adaptive-hooks/hardware-concurrency';
import { useMemoryStatus } from 'react-adaptive-hooks/memory';
import { useMediaCapabilitiesDecodingInfo } from 'react-adaptive-hooks/media-capabilities';

A first real use is picking a media element by connection type. The README's network example switches on effectiveConnectionType and falls through to a video for 4g and for the default case:

js
import React from 'react';
import { useNetworkStatus } from 'react-adaptive-hooks/network';

const MyComponent = () => {
  const { effectiveConnectionType } = useNetworkStatus();
  let media;
  switch (effectiveConnectionType) {
    case 'slow-2g':
      media = <img src='...' alt='low resolution' />;
      break;
    case '4g':
      media = <video muted controls>...</video>;
      break;
    default:
      media = <video muted controls>...</video>;
      break;
  }
  return <div>{media}</div>;
};

In a browser that supports the NetworkInformation API you should see effectiveConnectionType reflect the current connection. In one that does not, the hook falls back to whatever you pass as the initial argument, so pass one if you care about the result. The README's own SSR example is a single line:

js
const initialEffectiveConnectionType = '4g';
const { effectiveConnectionType } = useNetworkStatus(initialEffectiveConnectionType);

The same pattern applies to the other hooks: useSaveData(initialSaveData) with a boolean, and useMemoryStatus(initialMemoryStatus) with an object like { deviceMemory: 4 }.

Where react-adaptive-hooks breaks down

The first limitation is written into the README title itself: the project is marked "(experimental)". Treat any API surface here as something that can move. The second is browser support. Every hook except the CPU and media ones depends on an API that is not universally available, which is exactly why the initial-value arguments exist. If you call useNetworkStatus() with no argument on a browser without NetworkInformation, the README does not promise a meaningful value, and your switch statement will land in the default branch. That means your "low-end" path may never trigger on the devices you most want to target, which is the opposite of the intent. A third issue is granularity. deviceMemory is documented as approximate gigabytes, and numberOfLogicalProcessors is a raw count, so both are coarse proxies for whether a device can handle a heavy component. A four-core phone with little RAM and a four-core laptop are not the same target, and neither hook distinguishes them. Finally, the hooks report capability; the README presents adaptive resource loading, data-fetching and code-splitting as patterns you build with them.

How this differs from a media-query or user-agent approach

The obvious alternative is CSS media queries plus a user-agent check, and the difference is where the decision happens. Media queries react to viewport width, not to connection quality or memory, so a narrow window on a fast laptop and a narrow window on a slow phone look identical to them. User-agent sniffing does try to classify the device, but it classifies by identity rather than by measured capability, and it runs on the server or at the edge where the browser has not yet reported anything. react-adaptive-hooks pushes the decision into the component, after hydration, using values the browser itself exposes through NetworkInformation, DeviceMemory and hardwareConcurrency. That gives you a per-render branch instead of a build-time or edge-time guess. The cost is that the first paint cannot know the answer unless you feed it an initial value from a Client Hint, which is precisely the SSR path the README describes. A second alternative is to do nothing and ship one experience: fewer moving parts, no dependency, no fallback logic. If your app is small or your audience is uniform, that is a defensible choice, and this library will add branching you do not need.

Maintenance, versioning and the Apache-2.0 licence

The package is published as react-adaptive-hooks version 0.1.0, with main pointing at dist/index.js, module at dist/index.module.js and unpkg at dist/index.umd.js. The build is microbundle, and the scripts are build, dev, prepare, test and test:coverage, so the maintainers' own workflow is npm run build plus jest. The peer dependency is declared as react ^16.8.0 || ^17.0.0, which matters if your app is on a newer major. The repository is not archived, and the last push was on 2026-06-16. The repository has no published GitHub releases, so the version in package.json is the only version signal available. The licence is Apache-2.0, which permits commercial use and modification and requires that you retain the licence and notice files; it also includes a patent grant. That is a permissive arrangement, but it is not legal advice, and if you redistribute the package inside a product you should have your own counsel read the LICENSE file in the repository rather than relying on a summary. Upgrade cost is low in principle because the API is a handful of hooks, but the experimental marker means a minor version bump can change return shapes, and the subpath imports mean a rename of a directory would break your import statements.

Editorial conclusion

Adopt react-adaptive-hooks if you already render React on the client and want a single place to branch on effective connection type, Data Saver, device memory or logical CPU cores. Do not adopt it if you need guaranteed values in every browser: the README itself notes that the network, Data Saver and memory hooks accept an initial value precisely because the underlying APIs may be missing, and the package is marked experimental. Before wiring it into a production bundle, verify three things: that your target browsers expose the NetworkInformation, DeviceMemory and hardwareConcurrency APIs, that your server can supply the matching Client Hints for the initial arguments, and that the versions in package.json (version 0.1.0, peerDependencies react ^16.8.0 || ^17.0.0) match the React version your app actually runs.

Frequently asked questions

How do I install react-adaptive-hooks?

The README gives two equivalent commands: npm i react-adaptive-hooks --save, or yarn add react-adaptive-hooks. After that you import individual hooks from subpaths such as react-adaptive-hooks/network rather than from the package root.

What values can effectiveConnectionType take in react-adaptive-hooks?

The README states the values can be slow-2g, 2g, 3g or 4g. The network example switches on those strings and falls through to a default branch for anything else.

Does react-adaptive-hooks work with server-side rendering?

The README says the optional initial-value arguments exist partly for server-side rendering. You can pass an ECT Client Hint as initialEffectiveConnectionType, a Save-Data Client Hint converted to a boolean as initialSaveData, or a Device-Memory Client Hint as initialMemoryStatus.

Which React versions does react-adaptive-hooks support?

The package.json declares a peer dependency of react ^16.8.0 || ^17.0.0.

What is the licence for react-adaptive-hooks?

The repository and package.json both list Apache-2.0. The LICENSE file is in the repository root.

Official sources

  1. GoogleChromeLabs/react-adaptive-hooks on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/googlechromelabs-react-adaptive-hooks.svg)](https://hysenlabs.com/projects/googlechromelabs-react-adaptive-hooks)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/googlechromelabs-react-adaptive-hooks.svg)](https://hysenlabs.com/projects/googlechromelabs-react-adaptive-hooks)

Was this useful?