
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Wed, 15 Apr 2026 21:09:42 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Build your next video application on Cloudflare]]></title>
            <link>https://blog.cloudflare.com/build-video-applications-cloudflare/</link>
            <pubDate>Fri, 19 Nov 2021 13:59:21 GMT</pubDate>
            <description><![CDATA[ Today, we’re going to build a video application inspired by Cloudflare TV. We’ll have user authentication and the ability for administrators to upload recorded videos or livestream new content. Think about being able to build your own YouTube or Twitch using Cloudflare services! ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Historically, building video applications has been very difficult. There's a lot of complicated tech behind recording, encoding, and playing videos. Luckily, <a href="https://www.cloudflare.com/products/cloudflare-stream/">Cloudflare Stream</a> abstracts all the difficult parts away, so you can build custom video and streaming applications easily. Let's look at how we can combine Cloudflare Stream, Access, Pages, and Workers to create a high-performance video application with very little code.</p><p>Today, we’re going to build a video application inspired by <a href="https://cloudflare.tv/live">Cloudflare TV</a>. We’ll have user authentication and the ability for administrators to upload recorded videos or livestream new content. Think about being able to build your own YouTube or Twitch using Cloudflare services!</p><div></div>
    <div>
      <h3>Fetching a list of videos</h3>
      <a href="#fetching-a-list-of-videos">
        
      </a>
    </div>
    <p>On the main page of our application, we want to display a list of all videos. The videos are uploaded and stored with Cloudflare Stream, but more on that later! This code could be changed to display only the "trending" videos or a selection of videos chosen for each user. For now, we'll use the search API and pass in an empty string to return all.</p>
            <pre><code>import { getSignedStreamId } from "../../src/cfStream"

export async function onRequestGet(context) {
    const {
        request,
        env,
        params,
    } = context

    const { id } = params

    if (id) {
        const res = await fetch(`https://api.cloudflare.com/client/v4/accounts/${env.CF_ACCOUNT_ID}/stream/${id}`, {
            method: "GET",
            headers: {
                "Authorization": `Bearer ${env.CF_API_TOKEN_STREAM}`
            }
        })

        const video = (await res.json()).result

        if (video.meta.visibility !== "public") {
            return new Response(null, {status: 401})
        }

        const signedId = await getSignedStreamId(id, env.CF_STREAM_SIGNING_KEY)

        return new Response(JSON.stringify({
            signedId: `${signedId}`
        }), {
            headers: {
                "content-type": "application/json"
            }
        })
    } else {
        const url = new URL(request.url)
        const res = await (await fetch(`https://api.cloudflare.com/client/v4/accounts/${env.CF_ACCOUNT_ID}/stream?search=${url.searchParams.get("search") || ""}`, {
            headers: {
                "Authorization": `Bearer ${env.CF_API_TOKEN_STREAM}`
            }
        })).json()

        const filteredVideos = res.result.filter(x =&gt; x.meta.visibility === "public") 
        const videos = await Promise.all(filteredVideos.map(async x =&gt; {
            const signedId = await getSignedStreamId(x.uid, env.CF_STREAM_SIGNING_KEY)
            return {
                uid: x.uid,
                status: x.status,
                thumbnail: `https://videodelivery.net/${signedId}/thumbnails/thumbnail.jpg`,
                meta: {
                    name: x.meta.name
                },
                created: x.created,
                modified: x.modified,
                duration: x.duration,
            }
        }))
        return new Response(JSON.stringify(videos), {headers: {"content-type": "application/json"}})
    }
}</code></pre>
            <p>We'll go through each video, filter out any private videos, and pull out the metadata we need, such as the thumbnail URL, ID, and created date.</p>
    <div>
      <h3>Playing the videos</h3>
      <a href="#playing-the-videos">
        
      </a>
    </div>
    <p>To allow users to play videos from your application, they need to be public, or you'll have to sign each request. Marking your videos as public makes this process easier. However, there are many reasons you might want to control access to your videos. If you want users to log in before they play them or the ability to limit access in any way, mark them as private and use signed URLs to control access. You can find more information about securing your videos <a href="https://developers.cloudflare.com/stream/viewing-videos/securing-your-stream">here</a>.</p><p>If you are testing your application locally or expect to have fewer than 10,000 requests per day, you can call the /token endpoint to generate a signed token. If you expect more than 10,000 requests per day, sign your own tokens as we do here using <a href="https://jwt.io/">JSON Web Tokens</a>.</p>
    <div>
      <h3>Allowing users to upload videos</h3>
      <a href="#allowing-users-to-upload-videos">
        
      </a>
    </div>
    <p>The next step is to build out an admin page where users can upload their videos. You can find documentation on allowing user uploads <a href="https://developers.cloudflare.com/stream/uploading-videos/direct-creator-uploads">here</a>.</p><p>This process is made easy with the Cloudflare Stream API. You use your <a href="https://developers.cloudflare.com/api/tokens/create">API token</a> and account ID to generate a unique, one-time upload URL. Just make sure your token has the Stream:Edit permission. We hook into all POST requests from our application and return the generated upload URL.</p>
            <pre><code>export const cfTeamsAccessAuthMiddleware = async ({request, data, env, next}) =&gt; {
    try {
        const userEmail = request.headers.get("cf-access-authenticated-user-email")

        if (!userEmail) {
            throw new Error("User not found, make sure application is behind Cloudflare Access")
        }
  
        // Pass user info to next handlers
        data.user = {
            email: userEmail
        }
  
        return next()
    } catch (e) {
        return new Response(e.toString(), {status: 401})
    }
}

export const onRequest = [
    cfTeamsAccessAuthMiddleware
]</code></pre>
            <p>The admin page contains a form allowing users to drag and drop or upload videos from their computers. When a logged-in user hits submit on the upload form, the application generates a unique URL and then posts the <a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData">FormData</a> to it. This code would work well for building a video sharing site or with any application that allows user-generated content.</p>
            <pre><code>async function getOneTimeUploadUrl() {
    const res = await fetch('/api/admin/videos', {method: 'POST', headers: {'accept': 'application/json'}})
    const upload = await res.json()
    return upload.uploadURL
}

async function uploadVideo() {
    const videoInput = document.getElementById("video");

    const oneTimeUploadUrl = await getOneTimeUploadUrl();
    const video = videoInput.files[0];
    const formData = new FormData();
    formData.append("file", video);

    const uploadResult = await fetch(oneTimeUploadUrl, {
        method: "POST",
        body: formData,
    })
}</code></pre>
            
    <div>
      <h3>Adding real time video with Stream Live</h3>
      <a href="#adding-real-time-video-with-stream-live">
        
      </a>
    </div>
    <p>You can add a <a href="https://www.cloudflare.com/developer-platform/solutions/live-streaming/">livestreaming</a> section to your application as well, using <a href="/stream-live/">Stream Live</a> in conjunction with the techniques we've already covered.  You could allow logged-in users to start a broadcast and then allow other logged-in users, or even the public, to watch it in real-time! The streams will automatically save to your account, so they can be viewed immediately after the broadcast finishes in the main section of your application.</p>
    <div>
      <h3>Securing our app with middleware</h3>
      <a href="#securing-our-app-with-middleware">
        
      </a>
    </div>
    <p>We put all authenticated pages behind this middleware function. It checks the request headers to make sure the user is sending a valid authenticated user email.</p>
            <pre><code>export const cfTeamsAccessAuthMiddleware = async ({request, data, env, next}) =&gt; {
    try {
        const userEmail = request.headers.get("cf-access-authenticated-user-email")

        if (!userEmail) {
            throw new Error("User not found, make sure application is behind Cloudflare Access")
        }
  
        // Pass user info to next handlers
        data.user = {
            email: userEmail
        }
  
        return next()
    } catch (e) {
        return new Response(e.toString(), {status: 401})
    }
}

export const onRequest = [
    cfTeamsAccessAuthMiddleware
]</code></pre>
            
    <div>
      <h3>Putting it all together with Pages</h3>
      <a href="#putting-it-all-together-with-pages">
        
      </a>
    </div>
    <p>We have Cloudflare Access controlling our log-in flow. We use the Stream APIs to manage uploading, displaying, and watching videos. We use <a href="https://workers.cloudflare.com/">Workers</a> for managing fetch requests and handling API calls. Now it’s time to tie it all together using <a href="https://pages.cloudflare.com/">Cloudflare Pages</a>!</p><p>Pages provides an easy way to <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">deploy and host static websites</a>. But now, Pages seamlessly integrates with the Workers platform (link to announcement post). With this new integration, we can deploy this entire application with a single, readable repository.</p>
    <div>
      <h3>Controlling access</h3>
      <a href="#controlling-access">
        
      </a>
    </div>
    <p>Some applications are better public; others contain sensitive data and should be restricted to specific users. The main page is public for this application, and we've used <a href="https://www.cloudflare.com/teams/access/">Cloudflare Access</a> to limit the admin page to employees. You could just as easily use Access to protect the entire application if you’re building an internal learning service or even if you want to beta launch a new site!</p><p>When a user clicks the admin link on our <a href="https://cf-pages-stream.pages.dev/">demo site</a>, they will be prompted for an email address. If they enter a valid Cloudflare email, the application will send them an access code. Otherwise, they won't be able to access that page.</p><p>Check out the <a href="https://github.com/cloudflare/pages-stream-demo">source code</a> and get started building your own video application today!</p> ]]></content:encoded>
            <category><![CDATA[Full Stack Week]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Cloudflare Access]]></category>
            <category><![CDATA[Cloudflare Stream]]></category>
            <category><![CDATA[Video]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">6crZId6sbMVFWUz7qedA31</guid>
            <dc:creator>Jonathan Kuperman</dc:creator>
            <dc:creator>Adam Janiš</dc:creator>
        </item>
        <item>
            <title><![CDATA[Automatically generating types for Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/automatically-generated-types/</link>
            <pubDate>Tue, 16 Nov 2021 13:58:45 GMT</pubDate>
            <description><![CDATA[ Every time the Workers runtime code is built, a script runs over the public APIs and generates the Rust and TypeScript types as well as a JSON file containing an intermediate representation of the static types. The types are sent to the appropriate repositories and the JSON file is uploaded as well. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Historically, keeping our Rust and TypeScript type repos up to date has been hard. They were manually generated, which means they ran the risk of being inaccurate or out of date. Until recently, the workers-types repository needed to be manually updated whenever the types changed. We also used to add type information for mostly complete browser APIs. This led to confusion when people would try to use browser APIs that aren’t supported by the Workers runtime they would compile but throw errors.</p><p>That all changed this summer when Brendan Coll, whilst he was interning with us, built an automated pipeline for generating them. It runs every time we build the Workers runtime, generating types for our TypeScript and Rust repositories. Now everything is up-to-date and accurate.</p>
    <div>
      <h2>A quick overview</h2>
      <a href="#a-quick-overview">
        
      </a>
    </div>
    <p>Every time the Workers runtime code is built, a script runs over the public APIs and generates the Rust and TypeScript types as well as a JSON file containing an <a href="https://en.wikipedia.org/wiki/Intermediate_representation">intermediate representation</a> of the static types. The types are sent to the appropriate repositories and the JSON file is uploaded as well in case people want to create their own types packages. More on that later.</p><p>This means the static types will always be accurate and up to date. It also allows projects running Workers in other, statically-typed languages to generate their own types from our intermediate representation. Here is an example PR from our Cloudflare bot. It’s detected a change in the runtime types and is updating the TypeScript files as well as the intermediate representation.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7gGG9WJuWteHvOu7Gurphb/2c69778b60fc0be7b05de74620adc5ee/image2-12.png" />
            
            </figure>
    <div>
      <h2>Using the auto-generated types</h2>
      <a href="#using-the-auto-generated-types">
        
      </a>
    </div>
    <p>To get started, use wrangler to generate a new TypeScript project:</p>
            <pre><code>$ wrangler generate my-typescript-worker https://github.com/cloudflare/worker-typescript-template</code></pre>
            <p>If you already have a TypeScript project, you can install the latest version of <a href="https://github.com/cloudflare/workers-types">workers-types</a> with:</p>
            <pre><code>$ npm install --save-dev @cloudflare/workers-types</code></pre>
            <p>And then add <code>@cloudflare/workers-types</code> to your project's tsconfig.json file.</p>
            <pre><code>{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "lib": ["ES2020"],
    "types": ["@cloudflare/workers-types"]
  }
}</code></pre>
            <p>After that, you should get automatic type completion in your IDE of choice.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4qwl2tjaM5QenHDZi4Tat7/194c992e5b9bb9a35fbd4b94dcceb007/image3-19.png" />
            
            </figure>
    <div>
      <h2>How it works</h2>
      <a href="#how-it-works">
        
      </a>
    </div>
    <p>Here is some example code from the Workers runtime codebase.</p>
            <pre><code>class Blob: public js::Object {
public:
  typedef kj::Array&lt;kj::OneOf&lt;kj::Array&lt;const byte&gt;, kj::String, js::Ref&lt;Blob&gt;&gt;&gt; Bits;
  struct Options {
    js::Optional&lt;kj::String&gt; type;
    JS_STRUCT(type);
  };

  static js::Ref&lt;Blob&gt; constructor(js::Optional&lt;Bits&gt; bits, js::Optional&lt;Options&gt; options);
  
  int getSize();
  js::Ref&lt;Blob&gt; slice(js::Optional&lt;int&gt; start, js::Optional&lt;int&gt; end);

  JS_RESOURCE_TYPE(Blob) {
    JS_READONLY_PROPERTY(size, getSize);
    JS_METHOD(slice);
  }
};</code></pre>
            <p>A Python script runs over this code during each build and generates an <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">Abstract Syntax Tree</a> containing information about the function including an identifier, any argument types and any return types.</p>
            <pre><code>{
  "name": "Blob",
  "kind": "class",
  "members": [
    {
      "name": "size",
      "type": {
        "name": "integer"
      },
      "readonly": true
    },
    {
      "name": "slice",
      "type": {
        "params": [
          {
            "name": "start",
            "type": {
              "name": "integer",
              "optional": true
            }
          },
          {
            "name": "end",
            "type": {
              "name": "integer",
              "optional": true
            }
          }
        ],
        "returns": {
          "name": "Blob"
        }
      }
    }
  ]
}</code></pre>
            <p>Finally, the <a href="https://github.com/cloudflare/workers-types">TypeScript types</a> repositories are automatically sent PRs with the updated types.</p>
            <pre><code>declare type BlobBits = (ArrayBuffer | string | Blob)[];

interface BlobOptions {
  type?: string;
}

declare class Blob {
  constructor(bits?: BlobBits, options?: BlobOptions);
  readonly size: number;
  slice(start?: number, end?: number, type?: string): Blob;
}</code></pre>
            
    <div>
      <h3>Overrides</h3>
      <a href="#overrides">
        
      </a>
    </div>
    <p>In some cases, TypeScript supports concepts that our C++ runtime does not. Namely, generics and function overloads. In these cases, we override the generated types with partial declarations. For example, <code>DurableObjectStorage</code> makes heavy use of generics for its getter and setter functions.</p>
            <pre><code>declare abstract class DurableObjectStorage {
	 get&lt;T = unknown&gt;(key: string, options?: DurableObjectStorageOperationsGetOptions): Promise&lt;T | undefined&gt;;
	 get&lt;T = unknown&gt;(keys: string[], options?: DurableObjectStorageOperationsGetOptions): Promise&lt;Map&lt;string, T&gt;&gt;;
	 
	 list&lt;T = unknown&gt;(options?: DurableObjectStorageOperationsListOptions): Promise&lt;Map&lt;string, T&gt;&gt;;
	 
	 put&lt;T&gt;(key: string, value: T, options?: DurableObjectStorageOperationsPutOptions): Promise&lt;void&gt;;
	 put&lt;T&gt;(entries: Record&lt;string, T&gt;, options?: DurableObjectStorageOperationsPutOptions): Promise&lt;void&gt;;
	 
	 delete(key: string, options?: DurableObjectStorageOperationsPutOptions): Promise&lt;boolean&gt;;
	 delete(keys: string[], options?: DurableObjectStorageOperationsPutOptions): Promise&lt;number&gt;;
	 
	 transaction&lt;T&gt;(closure: (txn: DurableObjectTransaction) =&gt; Promise&lt;T&gt;): Promise&lt;T&gt;;
	}</code></pre>
            <p>You can also write type overrides using Markdown. <a href="https://github.com/cloudflare/workers-types/blob/master/docs/kv.md">Here</a> is an example of overriding types of <code>KVNamespace</code>.</p>
    <div>
      <h2>Creating your own types</h2>
      <a href="#creating-your-own-types">
        
      </a>
    </div>
    <p>The JSON IR (<a href="https://en.wikipedia.org/wiki/Intermediate_representation">intermediate representation</a>) has been open sourced alongside the TypeScript types and can be found <a href="https://github.com/cloudflare/workers-types/blob/master/src/workers.json">in this GitHub repository</a>. We’ve also open sourced the <a href="https://github.com/cloudflare/workers-types/blob/master/src/schema.json">type schema</a> itself, which describes the format of the IR. If you’re interested in generating Workers types for your own language, you can take the IR, which describes the declaration in a "normalized" data structure, and generate types from it.</p><p>The declarations inside <code>workers.json</code> contain the elements to derive function signatures and other elements needed for code generation such as identifiers, argument types, return types and error management. A concrete use-case would be to generate external function declarations for a language that compiles to WebAssembly, to import precisely the set of available function calls available from the Workers runtime.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>Cloudflare cares deeply about supporting the TypeScript and Rust ecosystems. Brendan created a tool which will ensure the type information for both languages is always up-to-date and accurate. We also are open-sourcing the type information itself in JSON format, so that anyone interested can create type data for any language they’d like!</p>
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div><p></p> ]]></content:encoded>
            <category><![CDATA[Full Stack Week]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">5s0jPmxdqjgqU9MVoG8A0w</guid>
            <dc:creator>Brendan Coll</dc:creator>
            <dc:creator>Jonathan Kuperman</dc:creator>
        </item>
        <item>
            <title><![CDATA[Get started Building Web3 Apps with Cloudflare]]></title>
            <link>https://blog.cloudflare.com/get-started-web3/</link>
            <pubDate>Fri, 01 Oct 2021 12:59:34 GMT</pubDate>
            <description><![CDATA[ Learn how to build Web3 applications with Cloudflare’s new open-source template. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/ob5X20V0l91LLtN25Jd4r/18cd9d69eee4cbcaaa21ea9afc3a9db5/image1-5.png" />
            
            </figure><p>For many developers, the term Web3 feels like a buzzword — it's the sort of thing you see on a popular "<i>Things you need to learn in 2021</i>" tweet. As a software developer, I've spent years feeling the same way. In the last few months, I’ve taken a closer look at the Web3 ecosystem, to better understand how it works, and why it matters.</p><p>Web3 can generally be described as a decentralized evolution of the Internet. Instead of a few providers acting as the mediators of how your interactions and daily life on the web should work, a Web3-based future would liberate your data from proprietary databases and operate without centralization via the incentive structure inherent in blockchains.</p><p>The Web3 space in 2021 looks and feels much different from what it did a few years ago. Blockchains like <a href="https://ethereum.org/en/">Ethereum</a> are handling incredible amounts of traffic with relative ease — although some improvements are needed — and newer blockchains like Solana have entered the space as genuine alternatives that could alleviate some of the scaling issues we've seen in the past few years.</p><p>Cloudflare is incredibly well-suited to empower developers to build the future with Web3. The announcement of <a href="/announcing-web3-gateways/">Cloudflare’s Ethereum gateway</a> earlier today will enable developers to build scalable Web3 applications on Cloudflare’s reliable network. Today, we’re also releasing an open-source example showing how to deploy, mint, and render NFTs, or non-fungible tokens, using <a href="https://workers.cloudflare.com">Cloudflare Workers</a> and <a href="https://pages.cloudflare.com">Cloudflare Pages</a>. You can <a href="https://cf-web3.pages.dev/">try it out here</a>, or check out the <a href="https://github.com/signalnerve/cfweb3">open-source codebase on GitHub</a> to get started deploying your own NFTs to production.</p>
    <div>
      <h3>The problem Web3 solves</h3>
      <a href="#the-problem-web3-solves">
        
      </a>
    </div>
    <p>When you begin to read about Web3 online, it's easy to get excited about the possibilities. As a software developer, I found myself asking: "<i>What actually is a Web3 application? How do I build one?</i>"</p><p>Most traditional applications make use of three pieces: the database, a code interface to that database, and the user interface. This model — best exemplified in the Model-View-Controller (MVC) architecture — has served the web well for decades. In MVC, the database serves as the storage system for your data models, and the controller determines how clients interact with that data. You define views with HTML, CSS and JavaScript that take that data and display it, as well as provide interactions for creating and updating that data.</p><p>Imagine a social media application with a billion users. In the MVC model, the data models for this application include all the user-generated content that are created daily: posts, friendships, events, and anything else. The controllers written for that application determine who can interact with that data internally; for instance, only the two users in a private conversation can access that conversation. But those controllers — and the application as a whole — don't allow external access to that data. The social media application owns that data and leases it out "for free" in exchange for viewing ads or being tracked across the web.</p><p>This was the lightbulb moment for me: understanding how Web3 offers a compelling solution to these problems. If the way MVC-based, Web 2.0 applications has presented itself is as a collection of "walled gardens" — meaning disparate, closed-off platforms with no interoperability or ownership of data — Web3 is, by design, the exact opposite.</p><p>In Web3 applications, there are effectively two pieces. The blockchain (let's use Ethereum as our example), and the user interface. The blockchain has two parts: an account, for a user, a group of users, or an organization, and the blockchain itself, which serves as an immutable system of record of everything taking place on the network.</p><p>One crucial aspect to understand about the blockchain is the idea that code can be deployed to that blockchain and that users of that blockchain can execute the code. In Ethereum, this is called a "smart contract". Smart contracts executed against the blockchain are like the controller of our MVC model. Instead of living in shrouded mystery, smart contracts are verifiable, and the binary code can be viewed by anyone.</p><p>For our hypothetical social media application, that means that any actions taken by a user are not stored in a central database. Instead, the user interacts with the smart contract deployed on the blockchain network, using a program that can be verified by anyone. Developers can begin building user interfaces to display that information and easily interact with it, with no walled gardens or platform lock-in. In fact, another developer could come up with a better user interface or smart contract, allowing users to move between these interfaces and contracts based on which aligns best with their needs.</p><p>Operating with these smart contracts happens via a wallet (for instance, an Ethereum wallet managed by <a href="https://metamask.io/">MetaMask</a>). The wallet is owned by a user and not by the company providing the service. This means you can take your wallet (the final authority on your data) and do what you want with it at any time. Wallets themselves are another programmable aspect of the blockchain — while they can represent a single user, they can also be complex multi-signature wallets that represent the interests of an entire organization. Owners of that wallet can choose to make consensus decisions about what to do with their data.</p><blockquote><p>people are talking trash about "web3" as a term,</p><p>but having all my data on multiple websites is cool</p><p>and having websites compete on interfaces for the same data is rad</p><p>— pm (@pm) <a href="https://twitter.com/pm/status/1434251123532070912?ref_src=twsrc%5Etfw">September 4, 2021</a></p></blockquote>
    <div>
      <h3>The rise of non-fungible tokens</h3>
      <a href="#the-rise-of-non-fungible-tokens">
        
      </a>
    </div>
    <p>One of the biggest recent shifts in the Web3 space has been the growth of NFTs — non-fungible tokens. Non-fungible tokens are unique assets stored on the blockchain that users can trade and verify ownership of. In 2019, Cloudflare was already writing about NFTs, as part of our <a href="/cloudflare-ethereum-gateway">announcement of the Cloudflare Ethereum Gateway</a>. Since then, NFTs have exploded in popularity, with projects like <a href="https://www.larvalabs.com/cryptopunks">CryptoPunks</a> and <a href="https://boredapeyachtclub.com/#/">Bored Ape Yacht Club</a> trading millions of dollars in volume monthly.</p><p>NFTs are a fascinating addition to the Web3 space because they represent how ownership of data and community can look in a post-walled garden world. If you've heard of NFTs before, you may know them as a very visual medium: CryptoPunks and Bored Ape Yacht Club are, at their core, art. You can buy a Punk or Ape and use it as your profile picture on social media. But underneath that, owning an Ape isn’t just owning a profile picture; they also have exclusive ownership of a blockchain-verified asset.</p><p>It should be noted that the proliferation of NFT contracts led to an increase in the number of <a href="https://www.theverge.com/22683766/nft-scams-theft-social-engineering-opensea-community-recovery">scams</a>. Blockchain-based NFTs are a medium of conveying ownership, based on a given smart contract. This smart contract can be deployed by anyone, and associated with any content. There is no guarantee of authenticity, until you verify the trustworthiness and identity of the contract you are interacting with. Some platforms may support <i>Verified</i> accounts, while others are only allowing a set of trusted partners to appear on their platform. NFTs are flexible enough to allow multiple approaches, but these trust assumptions have to be communicated clearly.</p><p>That asset, tied to a smart contract deployed on Ethereum, can be traded, verified, or used as a way to gate access to programs. An NFT developer can hook into the trade event for their NFTs and charge a royalty fee, or when "minting", or creating an NFT, they can charge a mint price, generating revenue on sales and trades to fund their next big project. In this way, NFTs can create strong incentive alignment between developers and community members, more so than your average web application.</p>
    <div>
      <h3>What we built</h3>
      <a href="#what-we-built">
        
      </a>
    </div>
    <p>To better understand Web3 (and how Cloudflare fits into the puzzle), we needed to build something using the Web3 stack, end-to-end.</p><p>To allow you to do the same, we’re open-sourcing a full-stack application today, showing you how to mint and manage an NFT from start to finish. <a href="https://rinkeby.etherscan.io/token/0x290422EC6eADc2CC12aCd98C50333720382CA86B">The smart contract for the application is deployed and verified</a> on Ethereum's <a href="https://www.rinkeby.io/">Rinkeby</a> network, which is a testing environment for Ethereum projects and smart contracts. The Rinkeby test network allows you to test the smart contract off of the main blockchain, using the exact same workflow, without using real ethers. When your project is ready to be deployed on Ethereum’s Mainnet, you can take the same contract, deploy and verify it, and begin using it in production.</p><p>Once deployed, the smart contract will provide the ability to manage your NFT project, compliant with <a href="https://eips.ethereum.org/EIPS/eip-721">the ERC-721 spec</a>, that can be minted by users, displayed on NFT marketplaces like <a href="https://opensea.io">OpenSea</a> and your own web applications. We also provided a web interface and example code for minting these NFTs — as a user, you can visit the web application with a compatible Ethereum wallet installed and claim a NFT.</p><p>Once you've minted the NFT, the example user interface will render the metadata for each claimed NFT. According to the ERC-721 (NFT) spec, a deployed token must have a corresponding URL that provides JSON metadata. This JSON endpoint, which we've built with Cloudflare Workers, returns a name and description for each unique NFT, as well as an image. To host this image, we've used Infura to pin the service, and Cloudflare IPFS Gateway to serve it. Our NFT identifies the content via its hash, making it not replaceable with something different in the future.</p><p>This open-source project provides all the tools that you need to build an NFT project. By building on Workers and Pages, you have all the tools you need to scale a successful NFT launch, and always provide up-to-date metadata for your NFT assets as users mint and trade them between wallets.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/J6PouNAVNlOShutQ8kwX9/01e5a2c22ff367481436b14f73a207e2/image2-3.png" />
            
            </figure><p>Architecture diagram of Cloudflare’s open-source NFT project</p>
    <div>
      <h3>Cloudflare + Web3</h3>
      <a href="#cloudflare-web3">
        
      </a>
    </div>
    <p>Cloudflare's developer platform — including Workers, Pages, and the IPFS gateway — works together to provide scalable solutions at each step of your NFT project's lifecycle. When you move your NFT project to production, Cloudflare’s <a href="/announcing-web3-gateways/">Ethereum</a> and <a href="/announcing-web3-gateways/">IPFS</a> gateways are available to handle any traffic that your project may have.</p><p>We're excited about Web3 at Cloudflare. The world is shifting back to a decentralized model of the Internet, the kind envisioned in the early days of the World Wide Web. As we say a lot around Cloudflare, <a href="/the-network-is-the-computer/">The Network is the Computer</a> — we believe that whatever form Web3 may take, whether through projects like Metaverses, DAOs (decentralized autonomous organizations) and NFTs for community and social networking, DeFi (decentralized finance) applications for managing money, and a whole class of decentralized applications that we probably haven't even thought of...  Cloudflare will be foundational to that future.</p> ]]></content:encoded>
            <category><![CDATA[Birthday Week]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">1xYnEmP6dc9MOQXD51cQKN</guid>
            <dc:creator>Kristian Freeman</dc:creator>
            <dc:creator>Jonathan Kuperman</dc:creator>
        </item>
    </channel>
</rss>