# Guideline 1.2 User-Generated Content: What Apple Requires

> Guideline 1.2: if your users post content, you need a filter, reporting, blocking, a contact and accepted terms. Expo and Supabase checklist.

Original page: [Guideline 1.2 User-Generated Content: What Apple Requires](https://devoria.fr/en/blog/guideline-1-2-user-generated-content-apple)
Author: [Mehdi Azizi](https://devoria.fr/en/mehdi-azizi)
Published: 2026-11-04
Content last revised: 2026-11-04


Guideline 1.2 applies as soon as users post something that other people can see: a message, a photo, a review, and, in my view, even just a username on a leaderboard. Apple's text then requires a filter, reporting with a quick response, blocking and a published contact. **Rejection messages add a fifth requirement: accepted terms of use that tolerate no objectionable content and no abusive users.**

This guide isn't the story of a rejection. It shows what I set up in TradaZen, my trading practice app, when its leaderboards started showing usernames picked by players. For the big picture on rejection reasons, read [why Apple rejects an app](https://devoria.fr/en/blog/apple-app-rejection-real-cases) instead.

## What does guideline 1.2 say?

Guideline 1.2, "User-Generated Content", sits in section 1, "Safety", of the [App Review Guidelines](https://developer.apple.com/app-store/review/guidelines/#user-generated-content). It covers apps with user content or a social networking service. To prevent abuse, these apps "must include" four safeguards:

- "A method for filtering objectionable material from being posted to the app": **a filter that blocks objectionable content before it gets posted**.
- "A mechanism to report offensive content and timely responses to concerns": a way to report content, and a quick response to reports.
- "The ability to block abusive users from the service": the ability to block an abusive user.
- "Published contact information so users can easily reach you": a published contact that's easy to find.

The current version of the text, updated on June 8, 2026, goes further. It reminds you that it's your responsibility to remove content that breaks the rule, your terms of use or your community guidelines. If Apple finds some, it asks you to remove it and provide an improvement plan, and it may pull the app in the meantime.

The text also lists apps that don't belong on the App Store: those used mainly for pornography, random or anonymous Chatroulette-style chat, rating real people's looks, threats or bullying. **For those uses, the four safeguards aren't enough.** Guideline 1.2.1 adds rules for creator apps, including an age check for content that goes beyond the app's rating.

## Does this apply to your app?

The age rating questionnaire in App Store Connect gives a good definition. It talks about [user-generated content](https://developer.apple.com/help/app-store-connect/reference/app-information/age-ratings-values-and-definitions) when content created by users is widely shared in the app: videos, photos, text or audio. It handles messaging between users separately.

| What others see           | Applies?        |
| ------------------------- | --------------- |
| Messages between members  | Yes             |
| Public photos or reviews  | Yes             |
| Username on a leaderboard | Yes, in my view |
| Private notes             | No              |
| Content you wrote         | No              |

Apple doesn't mention usernames. I still treat them as user content: anyone can pick an insulting one, and other players see it. That's the choice I made for TradaZen's leaderboards.

## The 5 mechanisms to build, with Expo and Supabase

The 1.2 rejection message, as one developer posted it on [Apple's forums](https://developer.apple.com/forums/thread/807358) in late 2025, lists the expected measures. It starts with "Require that users agree to terms (EULA)" and ends with a deadline: act on reports "within 24 hours", by removing the content and ejecting its author.

| Mechanism         | Where to build it         |
| ----------------- | ------------------------- |
| Accepted terms    | Screen and profile        |
| Filter            | Server, before display    |
| Reporting         | Button and table          |
| Blocking          | Table and access rule     |
| Published contact | App and App Store listing |

Adapt the SQL examples below to your schema. They rely on [Supabase row level security](https://supabase.com/docs/guides/database/postgres/row-level-security), which applies even if someone bypasses your app.

### 1. Accepted terms, with zero tolerance for abuse

Your terms of use must state in black and white that no objectionable content and no abusive users are tolerated. Sample clause, to have reviewed, not legal advice: "No offensive, hateful, sexual or harassing content is tolerated. Reported content may be removed and its author banned, without notice."

**A passive sentence under a sign-up button doesn't prove consent: ask for an explicit action.** A screen with a link to the terms and an "I agree" button, before the first post. Store the accepted date and version in the profile, then block posting as long as they're missing:

```sql
create policy "publier après les CGU" on public.posts
for insert to authenticated
with check (
  auth.uid() = author_id
  and exists (
    select 1 from public.profiles p
    where p.id = auth.uid() and p.cgu_acceptees_le is not null
  )
);
```

### 2. A filter before others see the content

The filter lives on the server, because app code can be bypassed. A copy in the app is only there to warn the user right away.

In TradaZen, a database function checks every username, and the app applies the same list to warn the player. I keep both identical. On the server side, an offensive username isn't rejected on write: **it's replaced with a neutral username on display, which avoids blocking someone over a false positive**.

False positives show up fast. In TradaZen, an early version of the filter censored first names like Dominique, Monique or Véronique, because they contain part of a swear word. The fix: match whole words, not word fragments. And since the app is sold in Japanese and Chinese, the filter covers those languages too.

### 3. Reporting, handled within 24 hours

Every piece of posted content has a "Report" button. In TradaZen, a username reported in the league leaderboard immediately shows up under a neutral label on the reporter's phone. The report then goes to the server, and it's resent later if the phone is offline.

On the database side, a reports table, one report per person per piece of content:

```sql
create table public.reports (
  id uuid primary key default gen_random_uuid(),
  reporter_id uuid not null references auth.users (id) on delete cascade,
  target_id uuid not null,
  reason text,
  created_at timestamptz not null default now(),
  unique (reporter_id, target_id)
);
alter table public.reports enable row level security;
create policy "mes signalements" on public.reports
for insert to authenticated
with check (auth.uid() = reporter_id);
```

In TradaZen, **a username reported by several players is replaced with a neutral username**, and reports are never shown to the reported person. A general precaution: the identifier used for reporting must not be editable by the content's author, or they can escape the hiding.

Automatic hiding doesn't replace your decision. To meet the 24 hours, get notified on every report: a [Supabase database webhook](https://supabase.com/docs/guides/database/webhooks) can call a server function that sends you a message. The key that lets you remove content stays on the server, as I explain in [secret API key in an Expo app](https://devoria.fr/en/blog/secret-api-key-expo-app-what-to-protect).

### 4. Blocking that works immediately

A blocks table, then an access rule that removes blocked people's content from the blocker's feed:

```sql
create policy "sans les bloqués" on public.posts
for select to authenticated
using (
  not exists (
    select 1 from public.blocks b
    where b.blocker_id = auth.uid() and b.blocked_id = posts.author_id
  )
);
```

In TradaZen, you add a friend with a code, and you can remove and block them. **A blocked friend disappears from the list, even if they send a new request.**

### 5. A published contact that's easy to find

Put a contact address in the app's settings, and a support URL that actually responds in App Store Connect. In TradaZen, the support address appears in the privacy policy and in the terms of use. What those pages should contain is covered in [app privacy policy](https://devoria.fr/en/blog/app-privacy-policy-ios-apple-requirements).

One last point: decide what happens to the content of someone who deletes their account. The `on delete cascade` above deletes their reports along with their account. The full recipe is in [iOS account deletion](https://devoria.fr/en/blog/ios-account-deletion-flow-test-app-review).

## What TradaZen shows in its policy

These mechanisms are described publicly in TradaZen's privacy policy, updated in September 2026 when leagues and friends arrived: "Usernames go through an automatic filter; you can report an inappropriate username on the leaderboard, and remove and block a friend." The same policy states that email and journal are never shown to other players. The app's background is in the [TradaZen case study](https://devoria.fr/en/blog/tradazen-case-study-launching-iphone-app).

## How to reply to Apple after a 1.2 rejection

Tell the reviewer where to find each mechanism, in your reply and in the review notes. These features live in the app: the reviewer tests the code shipped in the build, so plan a new build. The process to [reply to App Review](https://developer.apple.com/help/app-store-connect/manage-submissions-to-app-review/reply-to-app-review-messages/) is the same as for other rules. Here's a template to adapt, keeping only what's true in your app:

```text
Hello,

Thank you for your review. Build X includes the precautions
listed in Guideline 1.2:

- Terms: users accept our terms, with zero tolerance for
  objectionable content and abusive users, before posting.
- Filter: posts and usernames are checked on our server
  before other users can see them.
- Report: tap "..." on any post, then "Report".
- Block: tap "..." on any post, then "Block user". Their
  content disappears immediately.
- Reports notify us instantly; we act on them within 24 hours.
- Contact: Settings > Contact us, and our support URL.

Best regards,
```

If a mechanism is missing from the build, a reply won't be enough. As with [guideline 2.1](https://devoria.fr/en/blog/guideline-2-1-app-store-rejection-fix), Apple judges the build it has in hand.

## The 1.2 checklist before submitting

- You've listed everything a user posts that others can see, usernames included.
- Your terms forbid objectionable content and abuse, and the app asks for an explicit "I agree".
- The filter runs on the server, matches whole words and covers your listing's languages.
- Every piece of content has a "Report" button, and every report notifies you right away.
- You can remove content and ban its author in under 24 hours.
- Blocking a user removes their content immediately.
- A contact address is visible in the app, and the support URL responds.
- The age rating questionnaire declares user content, and messaging if your app has it.
- The review notes say where to find each mechanism, with a demo account.

## Fix your rejection before resubmitting

If your app just got rejected under 1.2, the [Review Kit](https://devoria.fr/en/kits/app-review) brings together what I check before every submission, with two skills that review your project in Claude Code and draft your reply if Apple rejects you. For a human look, [book an hour with me](https://devoria.fr/en/coaching): we read the message together and go through your moderation flow. The full process after a rejection is on the [app rejected by Apple](https://devoria.fr/en/expertise/app-rejected-by-apple) page.

If you're preparing your first launch, [take your free diagnostic](https://devoria.fr/en/diagnostic): it tells you which step to tackle first and sends you my Apple anti-rejection checklist.

Nobody can guarantee Apple will accept your app. These five mechanisms, clearly visible, at least take this reason off the list.

## Frequently asked questions

### What does "Guideline 1.2 - Safety - User-Generated Content" mean?

That's the rejection title in Apple's message. It means your app shows user-created content without all the expected safeguards: filter, quickly handled reporting, blocking, published contact and accepted terms of use.

### Does a username on a leaderboard count as user content?

Apple's text doesn't say. I treat it as such, because a username is freely chosen and seen by other players. In TradaZen, leaderboard usernames go through a filter, can be reported and are replaced with a neutral username if they're a problem.

### Do you really have to handle reports within 24 hours?

That's what Apple's rejection message asks for. The rule's text talks about timely responses. So an automatic filter isn't enough: someone has to remove the content and ban its author. Automatic hiding after several reports helps you hold the line in the meantime.

### Do the terms of use have to be accepted in the app?

It's the safest way. The rejection message asks that users agree to terms that tolerate no objectionable content and no abusive users. A link at the bottom of a page doesn't prove consent. A screen with an "I agree" button, before the first post, leaves no doubt.

### Can an anonymous chat app pass guideline 1.2?

The current text lists random or anonymous chat among the uses that don't belong on the App Store. An app used mainly for that can be removed without notice, even with a filter, reporting and blocking.


## Your project

[Review Kit](https://devoria.fr/en/kits/app-review): My App Store review checklist, the Apple rejections I fixed, a Google Play checklist and three Claude Code skills. $55.

[iOS & Android Kit](https://devoria.fr/en/kits/ios): Build your iPhone and Android app with Claude Code: the starter code from my apps, the path all the way to the stores, and every kit. $109.

[Diagnostic: what's between you and your iPhone app](https://devoria.fr/en/diagnostic): 7 questions, 60 seconds: find out what's really stopping you from publishing your iPhone app, get your 4-step path and the kit that fits you.
