Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ build
.env.test.local
.env.production.local
.idea
.*.sw?

npm-debug.log*
yarn-debug.log*
Expand Down
49 changes: 49 additions & 0 deletions docs/api/redditapi/RedditAPIClient/classes/RedditAPIClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -2804,6 +2804,55 @@ const comment = await reddit.submitComment({

***

### submitCustomPost()

> **submitCustomPost**(`options`): `Promise`\<[`Post`](../../models/classes/Post.md)\>

Submits a new [interactive post](../../../../capabilities/interactive-posts/interactive_posts_overview.mdx) to a subreddit.

#### Parameters

##### options

[`SubmitCustomPostOptions`](../../models/type-aliases/SubmitCustomPostOptions.md)

Either a self post or a link post.

#### Returns

`Promise`\<[`Post`](../../models/classes/Post.md)\>

A Promise that resolves to a Post object.

#### Examples

```ts
const post = await reddit.submitCustomPost({
subredditName: 'devvit',
title: 'Hello World',
entry: 'default',
});
```

By default, `submitCustomPost()` creates a Post on behalf of the App account, but it may be called on behalf of the User making the request by setting the option `runAs: RunAs.USER`.
When using `runAs: RunAs.USER` to create an interactive post, you must specify the `userGeneratedContent` option. For example:

```ts
import { RunAs } from '@devvit/public-api';

const post = await reddit.submitCustomPost({
subredditName: await reddit.getCurrentSubredditName(),
title: 'My Devvit Post',
userGeneratedContent: {
text: "hello there",
imageUrls: ["https://styles.redditmedia.com/t5_5wa5ww/styles/communityIcon_wyopomb2xb0a1.png", "https://styles.redditmedia.com/t5_49fkib/styles/bannerBackgroundImage_5a4axis7cku61.png"]
},
runAs: RunAs.USER,
});
```

***

<a id="submitpost"></a>

### submitPost()
Expand Down
76 changes: 76 additions & 0 deletions docs/capabilities/server/userActions.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ By default, apps make posts or comments using their associated app account. With

---

## Available user actions

These actions can be made on behalf of the user:

| Action | Permission scope |
| :--- | :--- |
| [submitCustomPost()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#submitcustompost) | `SUBMIT_POST` |
| [submitPost()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#submitpost) | `SUBMIT_POST` |
| [submitComment()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient.md#submitcomment) | `SUBMIT_COMMENT` |
| [subscribeToCurrentSubreddit()](../../api/redditapi/RedditAPIClient/classes/RedditAPIClient#subscribetocurrentsubreddit) | `SUBSCRIBE_TO_SUBREDDIT` |

Each permission scope your app uses must be declared in your `devvit.json` ([enabling user actions](#enabling-user-actions)).

Your app must also [collect permission from the user](#collecting-permission-from-the-user). before you can perform actions on their behalf.

---

## Guidelines

To ensure a positive user experience and compliance with Reddit policies:
Expand Down Expand Up @@ -54,6 +71,8 @@ To enable user actions, add the required permissions to your `devvit.json`:
}
```

You should only include the permissions your app actually uses.

After enabling, you can call certain Reddit APIs on behalf of the user by passing the option `runAs: 'USER'`.

Currently, the following APIs support this option:
Expand All @@ -78,6 +97,63 @@ Apps that use `submitPost()` with `runAs: 'USER'` require `userGeneratedContent`

---

## Collecting permission from the user

The app must call `canRunAsUser()` _on the client side_ before it performs any fetch to
itself on the server side that might result in the use of any user action. This call
serves to collect permission from the user, and to inform the app of the user's decision.

The first time a user encounters a call to this function, they will be presented with
a consent dialog. All the permission scopes declared in `devvit.json` will be listed,
and the user will be asked to approve or deny.

If the user chooses approve, then `canRunAsUser()` will resolve its promise to `true`,
and you may proceed with using any permitted user action on the server side.

If the user chooses deny, then the returned promise resolves to `false`. This may also
happen if the user chooses to revoke permission from their settings page anytime at a
later date. Use this check as an opportunity to continue providing non-consenting users
a quality experience, instead of exposing them to a permission check error from the
server side moments later.

Once the user has chosen one way or the other, future calls to `canRunAsUser()` will
resolve immediately, without prompting the user any further.

:::note
We currently do not _require_ collected permissions, but that will be changing soon!
If your app is already using `canRunAsUser()` properly, then it won't be impacted
when enforcement begins.
:::

```ts
import { canRunAsUser } from '@devvit/web/client';

// Button that user interacts with to share their result as a comment
function handleButtonClick() {
if (await canRunAsUser()) {
try {
const response = await fetch('/api/submit-comment');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
showToast({
text: 'Comment submitted',
appearance: 'success',
});
} catch (error) {
showToast('Something went wrong. Please try again.');
}
} else {
showToast({
text: 'Skipping comment submission because permission not granted',
appearance: 'success',
});
}
}
```

---

## Example: Submit a post as the user

This example uses a form to prompt the user for input and then submits a post as the user.
Expand Down