diff --git a/README.md b/README.md
index 3698a1f..4e48155 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,7 @@ Here is the list of all utilities:
- [Lorem Ipsum Generator](https://jam.dev/utilities/lorem-ipsum-generator)
- [WebP Converter](https://jam.dev/utilities/webp-converter)
- [SQL Minifer](https://jam.dev/utilities/sql-minifier)
+- [Internet Speed Test]("https://jam.dev/utilities/internet-speed-test")
### Built With
diff --git a/components/seo/InternetSpeedTestSEO.tsx b/components/seo/InternetSpeedTestSEO.tsx
new file mode 100644
index 0000000..488d3f9
--- /dev/null
+++ b/components/seo/InternetSpeedTestSEO.tsx
@@ -0,0 +1,149 @@
+export default function InternetSpeedTestSEO() {
+ return (
+
+
+
+ Test your internet connection speed with our free, accurate internet
+ speed test tool. Measure your download and upload speeds, latency, and
+ connection quality instantly. Powered by Cloudflare's global network
+ for reliable results.
+
+
+
+
+ How to Use the Internet Speed Test
+
+ Our speed test tool provides comprehensive internet connection
+ measurements using Cloudflare's edge network. Simply click the "Start"
+ button and wait for the test to complete - no signup or installation
+ required.
+
+
+ The test measures multiple aspects of your connection including
+ download speed, upload speed, latency, and jitter. Results are
+ displayed in real-time.
+
+
+
+
+ Understanding Your Speed Test Results
+
+ Internet speed tests measure several key metrics that affect your
+ online experience. Understanding these metrics helps you determine if
+ your connection meets your needs.
+
+
+ -
+ Download Speed:
+ How fast data transfers from the internet to your device. Important
+ for streaming, downloading files, and web browsing. Measured in Mbps
+ (megabits per second).
+
+ -
+ Upload Speed:
+ How fast data transfers from your device to the internet. Critical
+ for video calls, uploading files, and live streaming. Usually slower
+ than download speed for most connections.
+
+ -
+ Latency (Ping):
+ The time it takes for data to travel to a server and back. Lower
+ latency means more responsive connections. Measured in milliseconds
+ (ms). Important for gaming and video calls.
+
+ -
+ Jitter:
+ The variation in latency over time. Lower jitter means more stable
+ connections. High jitter can cause issues with real-time
+ applications like gaming and video calls.
+
+
+
+
+
+ Internet Speed Requirements
+
+ Different online activities require different internet speeds. Here's
+ what you need for common activities:
+
+
+ -
+ Basic web browsing and email: 1-5 Mbps
+
+ -
+ HD video streaming: 5-25 Mbps
+
+ -
+ 4K video streaming: 25-50 Mbps
+
+ -
+ Online gaming: 3-6 Mbps (with low latency)
+
+ -
+ Video calls: 1-8 Mbps
+
+ -
+ Large file downloads: 50+ Mbps
+
+
+
+
+
+ Why Use Cloudflare Speed Test?
+
+ Our speed test uses Cloudflare's global network, which provides more
+ accurate results than traditional speed tests. Cloudflare has servers
+ in over 200 cities worldwide, so you're likely testing against a
+ server close to your location.
+
+
+ The test is performed directly in your browser using modern web APIs,
+ ensuring accurate measurements of your actual browsing experience. No
+ plugins or software installations required.
+
+
+
+
+ FAQs
+
+ -
+ How accurate is this speed test?
+ Our speed test uses Cloudflare's global CDN network, providing
+ highly accurate results by testing against servers close to your
+ location. Results reflect real-world browsing performance.
+
+ -
+ Why might my speed test results vary?
+ Internet speeds can vary due to network congestion, time of day,
+ your device's performance, background applications, and your ISP's
+ current load. Run multiple tests for the most accurate average.
+
+ -
+ Should I close other applications before testing?
+ For the most accurate results, close applications that use the
+ internet (streaming, downloads, cloud sync) during the test. This
+ ensures the test measures your connection's full capacity.
+
+ -
+ What's a good internet speed?
+ It depends on your usage. For basic browsing: 5-10 Mbps. For HD
+ streaming: 25+ Mbps. For multiple users or 4K streaming: 50+ Mbps.
+ For heavy usage or multiple devices: 100+ Mbps.
+
+ -
+ Why is my upload speed slower than download?
+ Most internet plans are asymmetric, providing faster download than
+ upload speeds. This is because most users download more data
+ (streaming, browsing) than they upload.
+
+ -
+ Is this speed test free?
+ Yes, completely free with no registration required. No ads, no
+ tracking, and open source. Just like all our developer utilities at
+ Jam.
+
+
+
+
+ );
+}
diff --git a/components/utils/tools-list.ts b/components/utils/tools-list.ts
index ef41923..fe66855 100644
--- a/components/utils/tools-list.ts
+++ b/components/utils/tools-list.ts
@@ -149,4 +149,10 @@ export const tools = [
"Minify SQL by removing comments, extra spaces, and formatting for cleaner, optimized queries.",
link: "/utilities/sql-minifier",
},
+ {
+ title: "Internet Speed Test",
+ description:
+ "Test your internet connection speed with accurate measurements by using Cloudflare's global network.",
+ link: "/utilities/internet-speed-test",
+ },
];
diff --git a/package-lock.json b/package-lock.json
index 91b3505..8a7b5a2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "jam-dev-utilities",
"version": "0.1.0",
"dependencies": {
+ "@cloudflare/speedtest": "^1.6.0",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-icons": "^1.3.0",
@@ -659,6 +660,19 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "node_modules/@cloudflare/speedtest": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/speedtest/-/speedtest-1.6.0.tgz",
+ "integrity": "sha512-5EfTvWcDCAK6zOJpl7i4Ablzvxje7+dgVmhJxdK/uDuTIivyUVat/cCnxE67YYpuxKs+gbo569PbmHl+oI5eFA==",
+ "dependencies": {
+ "d3-scale": "^4.0.2",
+ "isomorphic-fetch": "^3.0.0",
+ "lodash.memoize": "^4.1.2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@@ -5278,6 +5292,81 @@
"node": ">=6"
}
},
+ "node_modules/d3-array": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-color": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-format": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
+ "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "dependencies": {
+ "d3-color": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-scale": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "dependencies": {
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "dependencies": {
+ "d3-array": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time-format": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "dependencies": {
+ "d3-time": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@@ -7370,6 +7459,14 @@
"node": ">= 0.4"
}
},
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -7842,6 +7939,15 @@
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
+ "node_modules/isomorphic-fetch": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz",
+ "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==",
+ "dependencies": {
+ "node-fetch": "^2.6.1",
+ "whatwg-fetch": "^3.4.1"
+ }
+ },
"node_modules/istanbul-lib-coverage": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
@@ -9114,8 +9220,7 @@
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
- "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
- "dev": true
+ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag=="
},
"node_modules/lodash.merge": {
"version": "4.6.2",
@@ -9511,7 +9616,6 @@
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
- "dev": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
@@ -9530,20 +9634,17 @@
"node_modules/node-fetch/node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
- "dev": true
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/node-fetch/node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
- "dev": true
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/node-fetch/node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "dev": true,
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
@@ -12389,6 +12490,11 @@
"node": ">=12"
}
},
+ "node_modules/whatwg-fetch": {
+ "version": "3.6.20",
+ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
+ "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="
+ },
"node_modules/whatwg-mimetype": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
diff --git a/package.json b/package.json
index 0f71bea..3d19d75 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"format:check": "prettier --check '**/*.{js,jsx,ts,tsx,json,css,scss,md}'"
},
"dependencies": {
+ "@cloudflare/speedtest": "^1.6.0",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-icons": "^1.3.0",
diff --git a/pages/utilities/internet-speed-test.tsx b/pages/utilities/internet-speed-test.tsx
new file mode 100644
index 0000000..e09d0ef
--- /dev/null
+++ b/pages/utilities/internet-speed-test.tsx
@@ -0,0 +1,249 @@
+import { useCallback, useRef, useState } from "react";
+import PageHeader from "@/components/PageHeader";
+import Header from "@/components/Header";
+import { CMDK } from "@/components/CMDK";
+import CallToActionGrid from "@/components/CallToActionGrid";
+import Meta from "@/components/Meta";
+import SpeedTestEngine from "@cloudflare/speedtest";
+import { Card } from "@/components/ds/CardComponent";
+import { cn } from "@/lib/utils";
+import InternetSpeedTestSEO from "@/components/seo/InternetSpeedTestSEO";
+
+type TestState = {
+ status: "idle" | "running" | "finished";
+ result: SpeedResult;
+};
+
+type SpeedResult = ReturnType<
+ typeof SpeedTestEngine.prototype.results.getSummary
+>;
+
+const createSpeedTestEngine = () => {
+ return new SpeedTestEngine({
+ autoStart: false,
+ measurements: [
+ // Quick latency check (1-2 seconds)
+ { type: "latency", numPackets: 5 },
+
+ // Download test (4-5 seconds)
+ { type: "download", bytes: 1e6, count: 2, bypassMinDuration: true },
+ { type: "download", bytes: 1e7, count: 1, bypassMinDuration: true },
+
+ // Upload test (4-5 seconds)
+ { type: "upload", bytes: 1e6, count: 2, bypassMinDuration: true },
+ { type: "upload", bytes: 1e7, count: 1, bypassMinDuration: true },
+ ],
+ });
+};
+
+const outlineStyles =
+ "outline outline-2 outline-green-500 outline-offset-2 shadow-md transition";
+
+export default function InternetSpeedTest() {
+ const [testState, setTestState] = useState