Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mikefolsom's avatar

SecurityError: Attempt to use history.replaceState() more than 100 times per 10 seconds

I am upgrading a project from Livewire 2 to Livewire 3, and it introduced an error in Safari that is also causing the page to break:

SecurityError: Attempt to use history.replaceState() more than 100 times per 10 seconds

Scenario: a page with a tabbed UI. Depending on the selected tab, different Livewire components are loaded. I am tracking the tab in the query string:

#[Url]
public $tab = 'follow-ups';

All works fine except for one user who has many nested ‘Task’ components on their ‘tasks’ tab. When activating that particular tab (‘Tasks’), Safari fails with the error listed above. (Chrome still works as expected.)

Ideas?

0 likes
1 reply
LaryAI's avatar
Level 58

The error you're encountering, SecurityError: Attempt to use history.replaceState() more than 100 times per 10 seconds, is a browser security feature to prevent excessive manipulation of the browser history, which can degrade performance and user experience.

In your scenario, it seems that the history.replaceState() method is being called excessively, likely due to the way Livewire is handling state updates for the nested 'Task' components. Here are a few steps you can take to mitigate this issue:

1. Debounce the State Updates

Debouncing the state updates can help reduce the frequency of history.replaceState() calls. You can use JavaScript to debounce these updates.

let debounceTimeout;
function debounceReplaceState(newState, title, url) {
    clearTimeout(debounceTimeout);
    debounceTimeout = setTimeout(() => {
        history.replaceState(newState, title, url);
    }, 100); // Adjust the delay as needed
}

2. Optimize Livewire Components

Ensure that your Livewire components are not causing unnecessary state updates. Review the lifecycle hooks and data bindings to minimize the number of updates.

3. Use Livewire's defer Modifier

If you are using Livewire's data binding, consider using the defer modifier to delay the updates until the user has finished interacting with the component.

<input wire:model.defer="tab" type="text">

4. Conditional State Updates

Only call history.replaceState() when there is an actual change in the state. This can be done by comparing the current state with the new state before making the call.

function safeReplaceState(newState, title, url) {
    if (history.state !== newState) {
        history.replaceState(newState, title, url);
    }
}

5. Review Livewire URL Handling

Since you are using the #[Url] attribute to track the tab in the query string, ensure that this is not causing excessive updates. You might need to adjust how often the URL is being updated.

Example Solution

Here is an example of how you might implement a debounced replaceState in your Livewire component:

// In your Livewire component
public function updatedTab($value)
{
    $this->emit('tabUpdated', $value);
}

// In your JavaScript
document.addEventListener('livewire:load', function () {
    Livewire.on('tabUpdated', function (tab) {
        debounceReplaceState({ tab: tab }, document.title, `?tab=${tab}`);
    });
});

By implementing these strategies, you should be able to reduce the frequency of history.replaceState() calls and avoid hitting the browser's security limit.

If the problem persists, consider isolating the issue further by simplifying the component structure or breaking down the nested components to identify the root cause of the excessive updates.

Please or to participate in this conversation.