|
| 1 | +# HTTP Fetch |
| 2 | + |
| 3 | +Make requests to allow-listed external domains. |
| 4 | + |
| 5 | +Your Devvit app can make network requests to access allow-listed external domains using HTTP Fetch. This enables your app to leverage webhooks, personal servers, and other third-party integrations asynchronously across the network. |
| 6 | + |
| 7 | +## Enabling HTTP fetch calls |
| 8 | + |
| 9 | +devvit.json |
| 10 | + |
| 11 | +``` |
| 12 | +
|
| 13 | +{ |
| 14 | + ... |
| 15 | + "permissions": { |
| 16 | + "http": { |
| 17 | + "enable": true, |
| 18 | + "domains": ["my-site.com", "another-domain.net"] |
| 19 | + } |
| 20 | + } |
| 21 | +} |
| 22 | +``` |
| 23 | + |
| 24 | +### Requesting a domain to be allow-listed |
| 25 | + |
| 26 | +Apps may request a domain to be added to the allow-list by specifying domains in the http configuration. This configuration is optional, and apps can still configure http: true as before. |
| 27 | + |
| 28 | +Requested domains will be submitted for review when you playtest or upload your app. Admins may approve or deny domain requests. |
| 29 | + |
| 30 | +Domain entries must be exact hostnames only, such as nytimes.com or wikipedia.org. These fetch requests are not allowed: |
| 31 | + |
| 32 | +* Be specific. No using \*.example.com when you need api.example.com |
| 33 | +* No wildcards: \*.example.com |
| 34 | +* No protocols: https://api.example.com |
| 35 | +* No paths: api.example.com/webhooks |
| 36 | + |
| 37 | +Domains that are approved for your app will be displayed in the Developer Settings section for your app at https://developers.reddit.com/apps/{your-app-slug}/developer-settings. These domains are allow-listed for **your app only** and not globally. |
| 38 | + |
| 39 | +Apps must request each individual domain that it intends to fetch, even if the domain is already globally allowed. See the [global fetch allowlist](https://developers.reddit.com/docs/capabilities/server/http-fetch#global-fetch-allowlist) to view the list of globally allowed domains. |
| 40 | + |
| 41 | +## Limitations |
| 42 | + |
| 43 | +* Access is only allowed to https URIs. |
| 44 | +* Supported HTTP methods: GET, POST, PUT, DELETE, OPTIONS and PATCH. |
| 45 | +* HTTP timeout limit is 30 seconds. |
| 46 | + |
| 47 | +## Example usage |
| 48 | + |
| 49 | +Devvit Web applications have two different contexts for using fetch: |
| 50 | + |
| 51 | +### Server-side fetch |
| 52 | + |
| 53 | +Server-side fetch allows your app to make HTTP requests to allowlisted external domains from your server-side code (e.g., API routes, server actions): |
| 54 | + |
| 55 | +server/index.ts |
| 56 | + |
| 57 | +``` |
| 58 | +
|
| 59 | +const response = await fetch('https://example.com/api/data', { |
| 60 | + method: 'GET', |
| 61 | + headers: { |
| 62 | + 'Content-Type': 'application/json', |
| 63 | + }, |
| 64 | +}); |
| 65 | +
|
| 66 | +const data = await response.json(); |
| 67 | +console.log('External API response:', data); |
| 68 | +``` |
| 69 | + |
| 70 | +### Client-side fetch |
| 71 | + |
| 72 | +Client-side fetch has different restrictions and can only make requests to your own webview domain: |
| 73 | + |
| 74 | +**Client-side restrictions:** |
| 75 | + |
| 76 | +* **Domain limitation**: Can only make requests to your own webview domain |
| 77 | +* **Endpoint requirement**: All requests must target endpoints that end with /api |
| 78 | +* **Authentication**: Handled automatically \- no need to manage auth tokens |
| 79 | +* **No external domains**: Cannot make requests to external domains from client-side code |
| 80 | + client/index.ts |
| 81 | + |
| 82 | +``` |
| 83 | +
|
| 84 | +const handleFetchData = async () => { |
| 85 | + // Correct: fetching your own webview's API endpoint |
| 86 | + const response = await fetch("/api/user-data", { |
| 87 | + method: "GET", |
| 88 | + headers: { |
| 89 | + "Content-Type": "application/json", |
| 90 | + }, |
| 91 | + }); |
| 92 | +
|
| 93 | + const data = await response.json(); |
| 94 | + console.log("API response:", data); |
| 95 | +}; |
| 96 | +
|
| 97 | +// Incorrect: cannot fetch external domains from client-side |
| 98 | +// const response = await fetch('https://external-api.com/data'); |
| 99 | +
|
| 100 | +// Incorrect: endpoint must end with /api |
| 101 | +// const response = await fetch('/user-data'); |
| 102 | +``` |
| 103 | + |
| 104 | +## Troubleshooting |
| 105 | + |
| 106 | +The following error means HTTP Fetch requests are hitting the internal timeout limits. To resolve this: |
| 107 | + |
| 108 | +* Use a queue or kick off an async request in your back end. You can use [Scheduler](https://developers.reddit.com/docs/capabilities/server/scheduler) to monitor the result. |
| 109 | +* Optimize the overall HTTP request latency if you have a self-hosted server. |
| 110 | + |
| 111 | +``` |
| 112 | +
|
| 113 | +HTTP request to domain: <domain> timed out with error: context deadline exceeded. |
| 114 | +``` |
| 115 | + |
| 116 | +## Global fetch allowlist |
| 117 | + |
| 118 | +These domains are globally allowed and can be fetched by any app. Expand to see full list. |
| 119 | + |
| 120 | +* api.massive.com |
| 121 | +* api.nasa.gov |
| 122 | +* api.openai.com |
| 123 | +* api.petfinder.com |
| 124 | +* api.polygon.io |
| 125 | +* api.scryfall.com |
| 126 | +* api.sportradar.com |
| 127 | +* api.sportradar.us |
| 128 | +* api.telegram.org |
| 129 | +* api.twitter.com |
| 130 | +* api.weather.gov |
| 131 | +* cdn.espn.com |
| 132 | +* chessboardjs.com |
| 133 | +* commentanalyzer.googleapis.com |
| 134 | +* discord.com |
| 135 | +* example.com |
| 136 | +* finance.yahoo.com |
| 137 | +* fonts.googleapis.com |
| 138 | +* generativelanguage.googleapis.com |
| 139 | +* i.giphy.com |
| 140 | +* language.googleapis.com |
| 141 | +* lichess.org |
| 142 | +* npr.org |
| 143 | +* nytimes.com |
| 144 | +* pbs.org |
| 145 | +* polygon.io |
| 146 | +* propublica.org |
| 147 | +* random.org |
| 148 | +* site.api.espn.com |
| 149 | +* slack.com |
| 150 | +* statsapi.mlb.com |
| 151 | +* wikipedia.org |
| 152 | +* youtube.googleapis.com |
| 153 | + |
| 154 | +## HTTP Fetch Policy |
| 155 | + |
| 156 | +Allow-listed domains fall into three categories: |
| 157 | + |
| 158 | +1. **APIs that provide data or specific services** (e.g., api.openai.com, api.wikipedia.org) \- These will be approved if they have a **publicly documented and publicly accessible API** for valid use cases, and if they adhere to the Devvit rules. Please reference our AI providers and account linking policies for common invalid use cases. |
| 159 | +2. **Limited scope cloud providers** (e.g., username.supabase.com, my-app.firebase.com) \- May be granted with exceptions. You must: |
| 160 | + * Follow user privacy guidelines and data governance requirements |
| 161 | + * Use an approved provider from the list below (please include your subdomain, and request for the most granular domain possible, e.g. my-app.s3.amazonaws.com) |
| 162 | + * supabase.com |
| 163 | + * firebase.com |
| 164 | + * spacetimedb.com |
| 165 | + * s3.amazonaws.com |
| 166 | + * storage.googleapis.com |
| 167 | + * Demonstrate a capability that @devvit/server doesn't support |
| 168 | + * Valid use cases include: |
| 169 | + * Asset hosting (videos, images, music) |
| 170 | + * Relational databases |
| 171 | + * Note: Approval can be revoked at any time |
| 172 | +3. **Personal domains** (e.g., personaldomain.com) \- Will not be approved. If you have a use case that our Devvit server does not support, please submit your request with detailed justification. |
| 173 | + |
| 174 | +### AI providers |
| 175 | + |
| 176 | +At this time, the OpenAI and Google Gemini are the only allowed providers: |
| 177 | + |
| 178 | +* api.openai.com |
| 179 | +* generativelanguage.googleapis.com |
| 180 | + |
| 181 | +Requests to use any other AI provider will be denied. |
| 182 | + |
| 183 | +### Documentation requirements |
| 184 | + |
| 185 | +If your app uses fetch domains, you must add context to your app's README for the approval process: |
| 186 | + |
| 187 | +1. Create a "Fetch Domains" section in your README |
| 188 | +2. List each domain you're requesting and explain why you need it |
| 189 | +3. Ensure your usage complies with our fetch guidelines |
| 190 | + |
| 191 | +Example README section: |
| 192 | + |
| 193 | +``` |
| 194 | +
|
| 195 | +## Fetch Domains |
| 196 | +
|
| 197 | +The following domains are requested for this app: |
| 198 | +
|
| 199 | +- `api.wikipedia.org` - Used to fetch article summaries for the knowledge base feature |
| 200 | +- `username.supabase.com` - Required for relational database storage of user preferences (Devvit KV store doesn't support complex queries needed for this feature) |
| 201 | +``` |
| 202 | + |
| 203 | +### Domain requirements |
| 204 | + |
| 205 | +Domain entries must be exact hostnames only, such as nytimes.com or wikipedia.org. In addition: |
| 206 | + |
| 207 | +* Be specific. No using \*.example.com when you need api.example.com |
| 208 | +* No wildcards: \*.example.com |
| 209 | +* No protocols: https://api.example.com |
| 210 | +* No paths: api.example.com/webhooks |
| 211 | + |
| 212 | +Domains that are approved for your app are displayed in the \[Developer Settings\](https://developers.reddit.com/apps/{your-app-slug}/developer-settings) section for your app. These domains are allow-listed for **your app only** and not globally. |
| 213 | + |
| 214 | +Apps must request each individual domain that it intends to fetch, even if the domain is already globally allowed. See the [global fetch allowlist](https://developers.reddit.com/docs/capabilities/server/http-fetch-policy#global-fetch-allowlist) to view the list of globally allowed domains. |
| 215 | + |
| 216 | +### Terms and conditions |
| 217 | + |
| 218 | +Any app that uses fetch must upload Terms and Conditions and a Privacy Policy. Links to each of these documents must be saved in the app details form. |
0 commit comments