---
area: "Learn"
parent: "Network & caching chapter"
url: "https://unpoly.com/learn/background-requests"
---
<nav aria-label="Unpoly docs">[All docs](https://unpoly.com/index.md) · [Network & caching chapter](https://unpoly.com/learn/network.md)</nav>

# Background requests

A background request is a request the user is not actively waiting for, like [preloading](https://unpoly.com/learn/preloading.md) a link or [polling](https://unpoly.com/learn/polling.md) a fragment. Background requests never show the [progress bar](https://unpoly.com/learn/progress-bar.md), and they wait while requests for the user's own clicks and submissions are sent first.

<nav aria-label="Contents">

#### Contents

- [What changes for a background request](#effects)
- [Which requests load in the background](#defaults)
- [Loading in the background](#opting-in)
- [When the user waits for a background request](#promotion)
- [Detecting background requests](#detecting)

</nav>

## What changes for a background request {#effects}

Unpoly treats a background request differently in two ways:

- **It never shows the progress bar.** A background request does not emit an [`up:network:late`](https://unpoly.com/api/up:network:late.md) event, no matter how long it takes. The [progress bar](https://unpoly.com/learn/progress-bar.md) only appears for requests the user is waiting for.
- **It has a lower priority.** Unpoly sends at most [6 requests](https://unpoly.com/api/up.network.config.md#config.concurrency) at the same time. When more requests are waiting, requests in the foreground are sent first. A background request is only sent when no foreground request is waiting.

Loading in the background does not change how a request is [aborted](https://unpoly.com/learn/aborting-requests.md), [cached](https://unpoly.com/learn/caching.md) or styled with [feedback classes](https://unpoly.com/learn/feedback-classes.md). [`up.network.isBusy()`](https://unpoly.com/api/up.network.isBusy.md) also returns `true` while a background request is loading.

## Which requests load in the background {#defaults}

The following requests load in the background by default:

- Requests from [preloading](https://unpoly.com/learn/preloading.md) a link.
- Requests from [polling](https://unpoly.com/learn/polling.md) a fragment.
- Requests that [revalidate](https://unpoly.com/learn/caching.md#revalidation) cached content after it was rendered.

Links, forms and [deferred content](https://unpoly.com/learn/lazy-loading.md) load in the foreground by default. A slow request from one of them shows the progress bar.

## Loading in the background {#opting-in}

To load a link, form or deferred element in the background, set an [`[up-background]`](https://unpoly.com/api/up-follow.md#up-background) attribute. From JavaScript, pass a [`{ background: true }`](https://unpoly.com/api/up.render.md#options.background) option to a rendering function or to [`up.request()`](https://unpoly.com/api/up.request.md).

For example, a form that publishes a post can save a draft while the user types. The user is not waiting for the draft to be saved, so it should not show the progress bar or delay the user's clicks:

```html
<form method="post" action="/posts" data-autosave="/drafts">
  <textarea name="text"></textarea>
  <button type="submit">Publish</button>
</form>
```

A [compiler](https://unpoly.com/learn/enhancing-elements.md) watches the form and sends its fields to the draft URL in the background:

```js
up.compiler('form[data-autosave]', function(form, { autosave: url }) {
  up.watch(form, { delay: 2000 }, function() {
    up.request(url, { method: 'post', params: up.Params.fromForm(form), background: true })
  })
})
```

To load a [polling](https://unpoly.com/learn/polling.md) request in the foreground, set `[up-background="false"]` on the [`[up-poll]`](https://unpoly.com/api/up-poll.md) element.

## When the user waits for a background request {#promotion}

Sometimes the user needs the response of a request that is still loading in the background. For example, the user hovers over a link and Unpoly starts [preloading](https://unpoly.com/learn/preloading.md) it. Before the preload request has finished, the user clicks the link.

Unpoly does not make a second request in this case. The click reuses the preload request from the [cache](https://unpoly.com/learn/caching.md), and the preload request is moved into the foreground. From then on it is treated like any other foreground request:

- When the request takes longer than [usual](https://unpoly.com/learn/progress-bar.md#timing), the progress bar appears.
- When the request is still waiting to be sent, it is sent before any background request.

This happens whenever a foreground request reuses a cached request that is still loading in the background.

## Detecting background requests {#detecting}

To check if a request is loading in the background, read its [`up.Request#background`](https://unpoly.com/api/up.Request.prototype.background.md) property. Network events like [`up:request:load`](https://unpoly.com/api/up:request:load.md) or [`up:fragment:loaded`](https://unpoly.com/api/up:fragment:loaded.md) give you the request as `event.request`.

For example, an app that warns users before their session times out may restart its idle timer with every request. Requests from polling or preloading are not user activity, so the listener skips them:

```js
up.on('up:request:load', function(event) {
  if (!event.request.background) {
    restartIdleTimer()
  }
})
```

The property is `false` for a background request that was moved into the [foreground](#promotion).

<nav aria-label="Reading order">

- [Previous: Aborting requests](https://unpoly.com/learn/aborting-requests.md)
- [Next: Handling network issues](https://unpoly.com/learn/network-issues.md)

</nav>

