From fd4babd1150bbd279649a644c1168b038cdfbe7e Mon Sep 17 00:00:00 2001 From: Xenc5 Date: Sun, 25 Jan 2026 00:27:09 +0000 Subject: [PATCH 1/5] Add requirements for User Actions --- docs/capabilities/server/userActions.md | 49 ++++++++++--------- .../capabilities/server/userActions.md | 49 ++++++++++--------- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/docs/capabilities/server/userActions.md b/docs/capabilities/server/userActions.md index adb44d0..7b0ee3f 100644 --- a/docs/capabilities/server/userActions.md +++ b/docs/capabilities/server/userActions.md @@ -1,6 +1,6 @@ -# User actions +# User Actions -User actions allow your app to perform certain actions—such as creating posts, comments, or subscribing to subreddits—on behalf of the user, rather than the app account. This enables stronger user engagement while ensuring user control and transparency. +User actions allow your app to submit posts, submit comments, and subscribe to the current subreddit on behalf of the logged in user. These actions occur on the logged in user's account instead of the app account. This enables stronger user engagement while ensuring user control and transparency. --- @@ -13,17 +13,19 @@ By default, apps make posts or comments using their associated app account. With --- -## Guidelines +Requirements +-------------- To ensure a positive user experience and compliance with Reddit policies: -- **Be transparent:** Inform users and show them the content that will be posted on their behalf. -- **No auto-creation:** Users must opt in to allow the app to post or comment on their behalf. This can only happen on an explicit action. -- **Provide user control:** If you are relying on persistent user opt-in, you must make it clear on how the user can opt-out. - +- **Always ask permission:** Your app must always inform users before posting, commenting, or subscribing on their behalf. This can only happen on an explicit manual action, e.g. from a button. +- **No automated actions:** Users must explicitly opt-in to the app acting on their behalf. Do not mislead or surprise users. +- **Establish a reporting flow:** Ensure `userGeneratedContent` is correctly set for posts submitted on behalf of the user. +- **Do not gate functionality behind subscribing:** Users should not be made to subscribe to the current subreddit to access any part of your app. +- **Remember the human:** Follow Reddit's safety and compliance guidelines for user-generated content. :::note -Apps using user actions must follow these guidelines to be approved. +Apps using user actions must follow these requirements to be approved. ::: --- @@ -110,26 +112,29 @@ router.post('/internal/post-create', async (_req, res) => { --- -## Example: Subscribe to subreddit +## Example: Subscribe to current subreddit + +The [subscribeToCurrentSubreddit()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#subscribetocurrentsubreddit) API does not take a `runAs` parameter; it subscribes as the user by default (if specified in `devvit.json` and approved). -The subscribe API does not take a `runAs` parameter; it subscribes as the user by default (if specified in `devvit.json` and approved). +It is first required to gain permission from the client with `canRunAsUser()`. ```ts -import { reddit } from '@devvit/web/server'; +import { canRunAsUser } from "@devvit/client"; -await reddit.subscribeToCurrentSubreddit(); +const result = await canRunAsUser(); ``` -:::note -There is no API to check if the user is already subscribed to the subreddit. You may want to store the subscription state in Redis to provide contextually aware UI. -::: +This shows a permissions request modal to the user, and returns a true or false value based on their choice. ---- +If the user has previously given permission to your app to subscribe, `canRunAsUser()` will return true without showing the request modal. -## Best practices +You can then call `subscribeToCurrentSubreddit()` on the server to complete the action. + + +```ts +import { reddit } from '@devvit/web/server'; + +await reddit.subscribeToCurrentSubreddit(); +``` -- Always inform users before posting or commenting on their behalf. -- Require explicit user opt-in for all user actions. -- Use `userGeneratedContent` for all user-submitted posts. -- Store user consent and subscription state if needed for your app's UX. -- Follow Reddit's safety and compliance guidelines for user-generated content. +For user privacy there is no API to check if the user is already subscribed to the current subreddit. You may want to store the subscription state in Redis to provide contextually aware UI. diff --git a/versioned_docs/version-0.12/capabilities/server/userActions.md b/versioned_docs/version-0.12/capabilities/server/userActions.md index adb44d0..7b0ee3f 100644 --- a/versioned_docs/version-0.12/capabilities/server/userActions.md +++ b/versioned_docs/version-0.12/capabilities/server/userActions.md @@ -1,6 +1,6 @@ -# User actions +# User Actions -User actions allow your app to perform certain actions—such as creating posts, comments, or subscribing to subreddits—on behalf of the user, rather than the app account. This enables stronger user engagement while ensuring user control and transparency. +User actions allow your app to submit posts, submit comments, and subscribe to the current subreddit on behalf of the logged in user. These actions occur on the logged in user's account instead of the app account. This enables stronger user engagement while ensuring user control and transparency. --- @@ -13,17 +13,19 @@ By default, apps make posts or comments using their associated app account. With --- -## Guidelines +Requirements +-------------- To ensure a positive user experience and compliance with Reddit policies: -- **Be transparent:** Inform users and show them the content that will be posted on their behalf. -- **No auto-creation:** Users must opt in to allow the app to post or comment on their behalf. This can only happen on an explicit action. -- **Provide user control:** If you are relying on persistent user opt-in, you must make it clear on how the user can opt-out. - +- **Always ask permission:** Your app must always inform users before posting, commenting, or subscribing on their behalf. This can only happen on an explicit manual action, e.g. from a button. +- **No automated actions:** Users must explicitly opt-in to the app acting on their behalf. Do not mislead or surprise users. +- **Establish a reporting flow:** Ensure `userGeneratedContent` is correctly set for posts submitted on behalf of the user. +- **Do not gate functionality behind subscribing:** Users should not be made to subscribe to the current subreddit to access any part of your app. +- **Remember the human:** Follow Reddit's safety and compliance guidelines for user-generated content. :::note -Apps using user actions must follow these guidelines to be approved. +Apps using user actions must follow these requirements to be approved. ::: --- @@ -110,26 +112,29 @@ router.post('/internal/post-create', async (_req, res) => { --- -## Example: Subscribe to subreddit +## Example: Subscribe to current subreddit + +The [subscribeToCurrentSubreddit()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#subscribetocurrentsubreddit) API does not take a `runAs` parameter; it subscribes as the user by default (if specified in `devvit.json` and approved). -The subscribe API does not take a `runAs` parameter; it subscribes as the user by default (if specified in `devvit.json` and approved). +It is first required to gain permission from the client with `canRunAsUser()`. ```ts -import { reddit } from '@devvit/web/server'; +import { canRunAsUser } from "@devvit/client"; -await reddit.subscribeToCurrentSubreddit(); +const result = await canRunAsUser(); ``` -:::note -There is no API to check if the user is already subscribed to the subreddit. You may want to store the subscription state in Redis to provide contextually aware UI. -::: +This shows a permissions request modal to the user, and returns a true or false value based on their choice. ---- +If the user has previously given permission to your app to subscribe, `canRunAsUser()` will return true without showing the request modal. -## Best practices +You can then call `subscribeToCurrentSubreddit()` on the server to complete the action. + + +```ts +import { reddit } from '@devvit/web/server'; + +await reddit.subscribeToCurrentSubreddit(); +``` -- Always inform users before posting or commenting on their behalf. -- Require explicit user opt-in for all user actions. -- Use `userGeneratedContent` for all user-submitted posts. -- Store user consent and subscription state if needed for your app's UX. -- Follow Reddit's safety and compliance guidelines for user-generated content. +For user privacy there is no API to check if the user is already subscribed to the current subreddit. You may want to store the subscription state in Redis to provide contextually aware UI. From b65d96e5f884b3fadd4cdd8dc905f5b5943deee3 Mon Sep 17 00:00:00 2001 From: Xenc5 Date: Sun, 25 Jan 2026 01:47:22 +0000 Subject: [PATCH 2/5] Add detailed subscribe example and explain support for custom posts --- docs/capabilities/server/userActions.md | 34 +++++++++++++++---- .../capabilities/server/userActions.md | 34 +++++++++++++++---- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/docs/capabilities/server/userActions.md b/docs/capabilities/server/userActions.md index 7b0ee3f..06b3968 100644 --- a/docs/capabilities/server/userActions.md +++ b/docs/capabilities/server/userActions.md @@ -61,6 +61,7 @@ After enabling, you can call certain Reddit APIs on behalf of the user by passin Currently, the following APIs support this option: - [submitPost()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#submitpost) +- [submitCustomPost()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#submitcustompost) - [submitComment()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#submitcomment) If `runAs` is not specified, the API will use `runAs: 'APP'` by default. @@ -116,16 +117,28 @@ router.post('/internal/post-create', async (_req, res) => { The [subscribeToCurrentSubreddit()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#subscribetocurrentsubreddit) API does not take a `runAs` parameter; it subscribes as the user by default (if specified in `devvit.json` and approved). -It is first required to gain permission from the client with `canRunAsUser()`. +It is first required to gain permission from the client with `canRunAsUser()`. This shows a permissions request modal to the user, and returns a true or false value based on their choice. ```ts -import { canRunAsUser } from "@devvit/client"; - -const result = await canRunAsUser(); +import { canRunAsUser, showToast } from "@devvit/client"; + +async function handleSubscribeButton() { + if (await canRunAsUser()) { + try { + const response = await fetch('/api/subscribe'); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + showToast({ text: 'Subscribed to community', appearance: 'success' }); + } catch (error) { + showToast('Something went wrong. Please try again.'); + } + } else { + showToast('Permission not granted'); + } +} ``` -This shows a permissions request modal to the user, and returns a true or false value based on their choice. - If the user has previously given permission to your app to subscribe, `canRunAsUser()` will return true without showing the request modal. You can then call `subscribeToCurrentSubreddit()` on the server to complete the action. @@ -134,7 +147,14 @@ You can then call `subscribeToCurrentSubreddit()` on the server to complete the ```ts import { reddit } from '@devvit/web/server'; -await reddit.subscribeToCurrentSubreddit(); +router.post('/api/subscribe', async (_req, res) => { + try { + await reddit.subscribeToCurrentSubreddit(); + res.json({ status: 'success' }); + } catch (error) { + res.status(500).json({ status: 'error', message: 'Failed to subscribe' }); + } +}); ``` For user privacy there is no API to check if the user is already subscribed to the current subreddit. You may want to store the subscription state in Redis to provide contextually aware UI. diff --git a/versioned_docs/version-0.12/capabilities/server/userActions.md b/versioned_docs/version-0.12/capabilities/server/userActions.md index 7b0ee3f..06b3968 100644 --- a/versioned_docs/version-0.12/capabilities/server/userActions.md +++ b/versioned_docs/version-0.12/capabilities/server/userActions.md @@ -61,6 +61,7 @@ After enabling, you can call certain Reddit APIs on behalf of the user by passin Currently, the following APIs support this option: - [submitPost()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#submitpost) +- [submitCustomPost()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#submitcustompost) - [submitComment()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#submitcomment) If `runAs` is not specified, the API will use `runAs: 'APP'` by default. @@ -116,16 +117,28 @@ router.post('/internal/post-create', async (_req, res) => { The [subscribeToCurrentSubreddit()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#subscribetocurrentsubreddit) API does not take a `runAs` parameter; it subscribes as the user by default (if specified in `devvit.json` and approved). -It is first required to gain permission from the client with `canRunAsUser()`. +It is first required to gain permission from the client with `canRunAsUser()`. This shows a permissions request modal to the user, and returns a true or false value based on their choice. ```ts -import { canRunAsUser } from "@devvit/client"; - -const result = await canRunAsUser(); +import { canRunAsUser, showToast } from "@devvit/client"; + +async function handleSubscribeButton() { + if (await canRunAsUser()) { + try { + const response = await fetch('/api/subscribe'); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + showToast({ text: 'Subscribed to community', appearance: 'success' }); + } catch (error) { + showToast('Something went wrong. Please try again.'); + } + } else { + showToast('Permission not granted'); + } +} ``` -This shows a permissions request modal to the user, and returns a true or false value based on their choice. - If the user has previously given permission to your app to subscribe, `canRunAsUser()` will return true without showing the request modal. You can then call `subscribeToCurrentSubreddit()` on the server to complete the action. @@ -134,7 +147,14 @@ You can then call `subscribeToCurrentSubreddit()` on the server to complete the ```ts import { reddit } from '@devvit/web/server'; -await reddit.subscribeToCurrentSubreddit(); +router.post('/api/subscribe', async (_req, res) => { + try { + await reddit.subscribeToCurrentSubreddit(); + res.json({ status: 'success' }); + } catch (error) { + res.status(500).json({ status: 'error', message: 'Failed to subscribe' }); + } +}); ``` For user privacy there is no API to check if the user is already subscribed to the current subreddit. You may want to store the subscription state in Redis to provide contextually aware UI. From b497bf10176268740041815b7c9a5958b15f8ad9 Mon Sep 17 00:00:00 2001 From: Xenc5 Date: Sun, 25 Jan 2026 01:52:02 +0000 Subject: [PATCH 3/5] Fix a missing comma in submit post example --- docs/capabilities/server/userActions.md | 4 ++-- .../version-0.12/capabilities/server/userActions.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/capabilities/server/userActions.md b/docs/capabilities/server/userActions.md index 06b3968..2395efb 100644 --- a/docs/capabilities/server/userActions.md +++ b/docs/capabilities/server/userActions.md @@ -103,8 +103,8 @@ router.post('/internal/post-create', async (_req, res) => { text: "Hello there! This is a new post from the user's account", }, subredditName, - title: 'Post Title' - entry: 'default', + title: 'Post Title', + entry: 'default', }); res.json({ status: 'success', message: `Post created in subreddit ${subredditName}` }); diff --git a/versioned_docs/version-0.12/capabilities/server/userActions.md b/versioned_docs/version-0.12/capabilities/server/userActions.md index 06b3968..2395efb 100644 --- a/versioned_docs/version-0.12/capabilities/server/userActions.md +++ b/versioned_docs/version-0.12/capabilities/server/userActions.md @@ -103,8 +103,8 @@ router.post('/internal/post-create', async (_req, res) => { text: "Hello there! This is a new post from the user's account", }, subredditName, - title: 'Post Title' - entry: 'default', + title: 'Post Title', + entry: 'default', }); res.json({ status: 'success', message: `Post created in subreddit ${subredditName}` }); From 6e26064ada8ba79086835f0eb034836befbfd18b Mon Sep 17 00:00:00 2001 From: Xenc5 Date: Sun, 25 Jan 2026 15:58:35 +0000 Subject: [PATCH 4/5] Update import to devvit/web/client in subscribe example --- docs/capabilities/server/userActions.md | 2 +- versioned_docs/version-0.12/capabilities/server/userActions.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/capabilities/server/userActions.md b/docs/capabilities/server/userActions.md index 2395efb..7ffa770 100644 --- a/docs/capabilities/server/userActions.md +++ b/docs/capabilities/server/userActions.md @@ -120,7 +120,7 @@ The [subscribeToCurrentSubreddit()](../../api/redditapi/RedditAPIClient/classes/ It is first required to gain permission from the client with `canRunAsUser()`. This shows a permissions request modal to the user, and returns a true or false value based on their choice. ```ts -import { canRunAsUser, showToast } from "@devvit/client"; +import { canRunAsUser, showToast } from '@devvit/web/client'; async function handleSubscribeButton() { if (await canRunAsUser()) { diff --git a/versioned_docs/version-0.12/capabilities/server/userActions.md b/versioned_docs/version-0.12/capabilities/server/userActions.md index 2395efb..7ffa770 100644 --- a/versioned_docs/version-0.12/capabilities/server/userActions.md +++ b/versioned_docs/version-0.12/capabilities/server/userActions.md @@ -120,7 +120,7 @@ The [subscribeToCurrentSubreddit()](../../api/redditapi/RedditAPIClient/classes/ It is first required to gain permission from the client with `canRunAsUser()`. This shows a permissions request modal to the user, and returns a true or false value based on their choice. ```ts -import { canRunAsUser, showToast } from "@devvit/client"; +import { canRunAsUser, showToast } from '@devvit/web/client'; async function handleSubscribeButton() { if (await canRunAsUser()) { From 79016a23d7143901ad4b74a3f587c05e1c9dba4e Mon Sep 17 00:00:00 2001 From: Xenc5 Date: Mon, 26 Jan 2026 23:26:45 +0000 Subject: [PATCH 5/5] Remove canRunAsUser example --- docs/capabilities/server/userActions.md | 27 ------------------- .../capabilities/server/userActions.md | 27 ------------------- 2 files changed, 54 deletions(-) diff --git a/docs/capabilities/server/userActions.md b/docs/capabilities/server/userActions.md index 7ffa770..0416b33 100644 --- a/docs/capabilities/server/userActions.md +++ b/docs/capabilities/server/userActions.md @@ -117,33 +117,6 @@ router.post('/internal/post-create', async (_req, res) => { The [subscribeToCurrentSubreddit()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#subscribetocurrentsubreddit) API does not take a `runAs` parameter; it subscribes as the user by default (if specified in `devvit.json` and approved). -It is first required to gain permission from the client with `canRunAsUser()`. This shows a permissions request modal to the user, and returns a true or false value based on their choice. - -```ts -import { canRunAsUser, showToast } from '@devvit/web/client'; - -async function handleSubscribeButton() { - if (await canRunAsUser()) { - try { - const response = await fetch('/api/subscribe'); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - showToast({ text: 'Subscribed to community', appearance: 'success' }); - } catch (error) { - showToast('Something went wrong. Please try again.'); - } - } else { - showToast('Permission not granted'); - } -} -``` - -If the user has previously given permission to your app to subscribe, `canRunAsUser()` will return true without showing the request modal. - -You can then call `subscribeToCurrentSubreddit()` on the server to complete the action. - - ```ts import { reddit } from '@devvit/web/server'; diff --git a/versioned_docs/version-0.12/capabilities/server/userActions.md b/versioned_docs/version-0.12/capabilities/server/userActions.md index 7ffa770..0416b33 100644 --- a/versioned_docs/version-0.12/capabilities/server/userActions.md +++ b/versioned_docs/version-0.12/capabilities/server/userActions.md @@ -117,33 +117,6 @@ router.post('/internal/post-create', async (_req, res) => { The [subscribeToCurrentSubreddit()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#subscribetocurrentsubreddit) API does not take a `runAs` parameter; it subscribes as the user by default (if specified in `devvit.json` and approved). -It is first required to gain permission from the client with `canRunAsUser()`. This shows a permissions request modal to the user, and returns a true or false value based on their choice. - -```ts -import { canRunAsUser, showToast } from '@devvit/web/client'; - -async function handleSubscribeButton() { - if (await canRunAsUser()) { - try { - const response = await fetch('/api/subscribe'); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - showToast({ text: 'Subscribed to community', appearance: 'success' }); - } catch (error) { - showToast('Something went wrong. Please try again.'); - } - } else { - showToast('Permission not granted'); - } -} -``` - -If the user has previously given permission to your app to subscribe, `canRunAsUser()` will return true without showing the request modal. - -You can then call `subscribeToCurrentSubreddit()` on the server to complete the action. - - ```ts import { reddit } from '@devvit/web/server';