Skip to main content
3xx Redirection

303 See Other

The server is redirecting the client to a different resource, and the client MUST use a GET request to fetch it.

Meaning & Description

The HTTP `303 See Other` redirect status response code indicates that the redirects don't link to the newly uploaded resources, but to another page (such as a confirmation page or an upload progress page). This response code is usually sent back as a result of a `PUT` or `POST`.

The defining characteristic of a 303 redirect is that it strictly instructs the client to change the HTTP method to `GET` for the subsequent request, regardless of what method was originally used. This makes it the backbone of the POST/Redirect/GET (PRG) web development pattern, which prevents users from accidentally resubmitting forms if they refresh the page.

Common Causes

  • Implementing the POST/Redirect/GET (PRG) pattern.
  • Form submissions returning a success view.
  • Redirecting to a status polling endpoint after triggering a long-running task.

How to fix a 303 error

  1. Ensure the URL in the `Location` header is capable of handling a `GET` request.
  2. Verify that session state (like success flash messages) is preserved across the redirect, usually via cookies or server-side sessions.
  3. If the client incorrectly maintains a `POST` request on redirect, check if they are using an outdated HTTP client, or if you accidentally sent a `307 Temporary Redirect` instead.

Browser & SEO Behaviour

Browser Behavior

Upon receiving a 303, the browser will immediately drop the original request body and method, and issue a fresh `GET` request to the URL in the `Location` header. This prevents the "Confirm Form Resubmission" dialog if the user clicks refresh.

SEO Impact

Search engines rarely encounter 303s as they do not typically submit forms or execute POST requests. If they do, they will index the target URL, not the redirecting URL.

CDN Behavior

CDNs do not cache 303 responses, as they are typically the result of a state-changing POST request.

Code Examples

Raw HTTP
HTTP/1.1 303 See Other
Date: Mon, 12 Sep 2026 12:00:00 GMT
Location: /checkout/success
Content-Length: 0
Node.js (Express)
app.post('/form-submit', (req, res) => {
  // Process the form data here
  saveData(req.body);
  
  // Redirect to success page using 303 to force a GET request
  res.redirect(303, '/success');
});
Python (FastAPI)
from fastapi import FastAPI, Form
from fastapi.responses import RedirectResponse

app = FastAPI()

@app.post("/submit")
def submit_form(name: str = Form(...)):
    # Process data
    # Use 303 to ensure the browser uses GET for the /success route
    return RedirectResponse(url="/success", status_code=303)
Go
func submitHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method == http.MethodPost {
        // Process POST data...
        // Redirect using 303 See Other
        http.Redirect(w, r, "/success", http.StatusSeeOther)
    }
}
C# (ASP.NET Core)
[HttpPost("submit")]
public IActionResult SubmitForm([FromForm] FormData data)
{
    // Save data...
    // Redirect to a GET endpoint
    return RedirectPreserveMethod("/success"); // Note: In ASP.NET, standard Redirect() does a 302. For a true 303, you might need a custom ActionResult or use StatusCode(303).
    // Better: return StatusCode(303, new { Location = "/success" });
}
curl
curl -X POST -d "name=Alice" -I http://example.com/submit
# Adding -L follows the redirect, automatically switching to GET
curl -X POST -d "name=Alice" -I -L http://example.com/submit

Raw HTTP Response Example

HTTP Response
HTTP/1.1 303 See Other
Location: https://store.example.com/checkout/success
Content-Length: 0
Connection: close

Real-world Examples

Stripe API: Uses 303 redirects in Stripe Checkout to return users back to the merchant's success or cancel URLs after a payment attempt.
Ruby on Rails: Since Rails 7, 303 is the default status code for redirects following form submissions (Turbo requires this pattern).
Generic Web Forms: Virtually every well-designed web application uses 303 to prevent double-billing on checkout pages.

Frequently Asked Questions

What is the POST/Redirect/GET (PRG) pattern?

It is a web development design pattern. Instead of returning HTML directly after a POST request, the server returns a 303 redirect. The browser then makes a GET request to fetch the HTML. This prevents the user from accidentally resubmitting the form if they refresh the page.

Why use 303 instead of 302 for the PRG pattern?

While 302 often works because early browsers incorrectly changed POSTs to GETs, 303 is the explicitly correct standard for this behavior. It guarantees that any compliant client will drop the POST body and switch to a GET request.

Does a 303 redirect preserve the request body?

No, absolutely not. The defining feature of a 303 redirect is that it drops the request body and forces a standard GET request.

Can I use a 303 redirect after a GET request?

While technically valid, it is semantically incorrect. 303 means "the result of your action is elsewhere." For redirecting a standard GET request, you should use 301, 302, or 307.

How do I pass data to the redirected page in a PRG flow?

Since the request body is dropped, you must pass data via URL query parameters, cookies, or server-side session storage (often called "flash messages").

Did You Know?

The 303 status code was specifically invented in HTTP/1.1 to formalize the behavior that early web browsers were already doing illegally with the 302 status code.

Modern frontend frameworks like Next.js and Remix rely heavily on the PRG pattern and 303 redirects for their server actions and form mutations.

Developer Tips

  • Always use 303 for form submission redirects. It is the gold standard for preventing the dreaded "Are you sure you want to resubmit this form?" browser dialog.
  • Use "flash" session storage to pass success/error messages across the 303 redirect boundary.
  • If you need to redirect a POST request but WANT the client to maintain the POST method and body, use 307 Temporary Redirect instead of 303.

Interview Questions

These are questions you might face in a backend or API design interview that touch on HTTP 303.

Explain the POST/Redirect/GET pattern and which HTTP status code enables it.

The PRG pattern prevents duplicate form submissions. When a server successfully processes a POST request, it replies with a 303 See Other redirect. The browser then issues a GET request to the new URL. If the user hits refresh, they only refresh the GET request, not the POST.

What is the exact difference between 303 See Other and 307 Temporary Redirect?

303 explicitly forces the client to change the request method to GET and drop the request body. 307 explicitly forces the client to maintain the original HTTP method (e.g., POST) and keep the request body intact.

Why shouldn't you pass sensitive data in the query string during a 303 redirect?

Because the new URL (which uses GET) will be saved in the browser's history, server logs, and potentially referer headers. Sensitive data should be kept in a server-side session during the redirect.

Common Interview Mistakes

  • Failing to connect the 303 status code to the PRG (POST/Redirect/GET) pattern.
  • Thinking that 303 preserves the request payload.
  • Recommending 303 for permanent domain migrations (which should be 301).