> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uplink.build/llms.txt
> Use this file to discover all available pages before exploring further.

# HTTP Requests

> Make API calls from the mobile device with mobile-specific headers and IP

Make HTTP requests via the mobile device, useful for API calls that need to appear from a mobile IP address or with mobile-specific headers.

## Method

### `page.request()`

Performs an HTTP request through the device's network connection.

```typescript theme={null}
page.request(url: string, options?: RequestOptions): Result
```

**Parameters:**

* `url`: URL to make the request to
* `options` (optional): Request options

**Options:**

```typescript theme={null}
interface RequestOptions {
  method?: string                      // HTTP method (default: 'GET')
  headers?: Record<string, string>     // Request headers
  body?: string | ReadableStream       // Request body
  timeout?: number                     // Request timeout in milliseconds
}
```

**Returns:** `Result` object with:

* `value(options?)`: Promise that resolves to response data
* `stream`: Internal stream object
* `readable`: `ReadableStream<Uint8Array>` for streaming response body
* `bytes()`: Promise that consumes stream and returns `Uint8Array`
* `json()`: Promise that consumes stream and returns parsed JSON
* `close()`: Close the stream

**Examples:**

```typescript theme={null}
// Simple GET request
const result = await page.request('https://api.example.com/data')
const data = await result.value({ close: true })
console.log('Response:', data)

// POST request with JSON
const result = await page.request('https://api.example.com/submit', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token123'
  },
  body: JSON.stringify({ key: 'value' })
})
const response = await result.value({ close: true })

// With timeout
const result = await page.request('https://slow-api.example.com/data', {
  timeout: 30000  // 30 seconds
})
```

## Complete examples

### API calls with mobile headers

```typescript theme={null}
// Make API call that appears to come from mobile device
const result = await page.request('https://api.example.com/mobile-only', {
  method: 'GET',
  headers: {
    'User-Agent': 'MyApp/1.0 (iOS 17.2; iPhone)',
    'X-Device-Type': 'mobile',
    'Authorization': 'Bearer ' + authToken
  }
})

const data = await result.value({ close: true })
console.log('Mobile API response:', data)
```

### POST data to API

```typescript theme={null}
async function submitForm(formData) {
  const result = await page.request('https://api.example.com/forms', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(formData)
  })

  const response = await result.value({ close: true })

  if (response.status === 200) {
    console.log('Form submitted successfully')
    return response.data
  } else {
    throw new Error(`Form submission failed: ${response.status}`)
  }
}

await submitForm({
  name: 'John Doe',
  email: 'john@example.com',
  message: 'Hello!'
})
```

### Authenticated API requests

```typescript theme={null}
async function makeAuthenticatedRequest(endpoint, accessToken) {
  const result = await page.request(`https://api.example.com${endpoint}`, {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Accept': 'application/json'
    }
  })

  const response = await result.value({ close: true })
  return JSON.parse(response)
}

// Usage
const userData = await makeAuthenticatedRequest('/user/profile', token)
console.log('User profile:', userData)

const orders = await makeAuthenticatedRequest('/user/orders', token)
console.log('Orders:', orders)
```

### Download file

```typescript theme={null}
async function downloadFile(url) {
  const result = await page.request(url, {
    method: 'GET'
  })

  const responseData = await result.value({ close: true })

  // Save or process the file data
  console.log('Downloaded file, size:', responseData.length)
  return responseData
}

const fileData = await downloadFile('https://example.com/file.pdf')
```

### Streaming response

```typescript theme={null}
async function streamLargeResponse(url) {
  const result = page.request(url)

  // Get the readable stream
  const readable = result.readable

  // Process chunks as they arrive
  const reader = readable.getReader()

  while (true) {
    const { done, value } = await reader.read()

    if (done) {
      console.log('Stream complete')
      break
    }

    // Process chunk (value is Uint8Array)
    console.log('Received chunk, size:', value.length)
  }

  // Get final response metadata
  const response = await result.value()
  console.log('Response status:', response.status)
}

await streamLargeResponse('https://api.example.com/large-data')
```

### Get response as bytes

```typescript theme={null}
const result = page.request('https://api.example.com/binary-data')

// Get entire response as Uint8Array
const bytes = await result.bytes()
console.log('Response size:', bytes.length)

// Convert to string if needed
const text = new TextDecoder().decode(bytes)
```

### Get response as JSON

```typescript theme={null}
const result = page.request('https://api.example.com/data.json')

// Automatically parse JSON response
const data = await result.json()
console.log('Parsed data:', data)
```

### Upload file

```typescript theme={null}
async function uploadFile(fileData, filename) {
  // Create a readable stream from file data
  const stream = new ReadableStream({
    start(controller) {
      controller.enqueue(fileData)
      controller.close()
    }
  })

  const result = await page.request('https://api.example.com/upload', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/octet-stream',
      'X-Filename': filename
    },
    body: stream
  })

  const response = await result.value({ close: true })
  return response
}

const fileData = new Uint8Array([/* file bytes */])
await uploadFile(fileData, 'document.pdf')
```

### GraphQL query

```typescript theme={null}
async function graphqlQuery(query, variables = {}) {
  const result = await page.request('https://api.example.com/graphql', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      query,
      variables
    })
  })

  const response = await result.value({ close: true })
  const data = JSON.parse(response)

  if (data.errors) {
    throw new Error('GraphQL errors: ' + JSON.stringify(data.errors))
  }

  return data.data
}

// Usage
const data = await graphqlQuery(`
  query GetUser($id: ID!) {
    user(id: $id) {
      name
      email
    }
  }
`, { id: '123' })

console.log('User data:', data.user)
```

### Retry failed requests

```typescript theme={null}
async function requestWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      console.log(`Request attempt ${attempt}/${maxRetries}`)

      const result = await page.request(url, {
        ...options,
        timeout: 10000
      })

      const response = await result.value({ close: true })
      return response

    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error.message)

      if (attempt === maxRetries) {
        throw new Error(`Request failed after ${maxRetries} attempts`)
      }

      // Wait before retrying (exponential backoff)
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
    }
  }
}

const data = await requestWithRetry('https://api.example.com/data', {
  method: 'GET'
})
```

### Paginated API requests

```typescript theme={null}
async function fetchAllPages(baseUrl) {
  const allData = []
  let page = 1
  let hasMore = true

  while (hasMore) {
    const result = await page.request(`${baseUrl}?page=${page}&limit=100`, {
      method: 'GET',
      headers: {
        'Accept': 'application/json'
      }
    })

    const response = await result.value({ close: true })
    const data = JSON.parse(response)

    allData.push(...data.items)

    hasMore = data.hasMore
    page++

    console.log(`Fetched page ${page - 1}, total items: ${allData.length}`)
  }

  return allData
}

const allItems = await fetchAllPages('https://api.example.com/items')
console.log(`Fetched ${allItems.length} total items`)
```

### Check API availability

```typescript theme={null}
async function checkAPIHealth() {
  try {
    const result = await page.request('https://api.example.com/health', {
      method: 'GET',
      timeout: 5000
    })

    const response = await result.value({ close: true })

    if (response.status === 200) {
      console.log('API is healthy')
      return true
    } else {
      console.warn('API returned status:', response.status)
      return false
    }
  } catch (error) {
    console.error('API is down:', error.message)
    return false
  }
}

const isHealthy = await checkAPIHealth()
```

## Best practices

<AccordionGroup>
  <Accordion title="Set appropriate timeouts" icon="clock">
    Always set timeouts for requests to avoid hanging:

    ```typescript theme={null}
    const result = await page.request(url, {
      timeout: 30000  // 30 seconds
    })
    ```
  </Accordion>

  <Accordion title="Close responses" icon="xmark-circle">
    Call `value({ close: true })` to properly close the response:

    ```typescript theme={null}
    const data = await result.value({ close: true })
    ```
  </Accordion>

  <Accordion title="Handle errors" icon="triangle-exclamation">
    Wrap requests in try-catch blocks:

    ```typescript theme={null}
    try {
      const result = await page.request(url)
      const data = await result.value({ close: true })
    } catch (error) {
      console.error('Request failed:', error)
    }
    ```
  </Accordion>

  <Accordion title="Use mobile-specific headers" icon="mobile">
    Include appropriate headers for mobile API endpoints:

    ```typescript theme={null}
    const result = await page.request(url, {
      headers: {
        'User-Agent': 'MyApp/1.0',
        'X-Platform': 'mobile'
      }
    })
    ```
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Waiting" icon="hourglass" href="/api-reference/page/waiting">
    Wait for specific requests
  </Card>

  <Card title="Events" icon="bell" href="/api-reference/page/events">
    Monitor XHR/fetch requests
  </Card>

  <Card title="Cookies" icon="cookie" href="/api-reference/page/cookies">
    Manage request cookies
  </Card>

  <Card title="Page overview" icon="window-maximize" href="/api-reference/page/overview">
    Back to Page API overview
  </Card>
</CardGroup>
