Type something to search...
How to set up automatic logout for idle users in WordPress?

How to set up automatic logout for idle users in WordPress?

The easiest way to set up automatic logout for idle users in WordPress is to install a plugin such as Inactive Logout, set a timeout like 15 or 30 minutes, and optionally show a countdown warning before the session ends. If you prefer code, you can combine two pieces: the auth_cookie_expiration filter to shorten the overall session length, and a small custom plugin that tracks each session's last activity and logs the user out once they've been idle too long.

Automatic logout protects your site when someone walks away from a logged-in computer, especially on shared or public devices. In this guide, you'll learn the difference between session length and idle timeout, how to set up idle logout with a plugin, how to build it yourself with WordPress APIs, and how to avoid frustrating your editors by logging them out in the middle of writing a post.

Why Log Out Idle Users?

By default, a WordPress login lasts two days, or 14 days if the user ticks Remember Me. During that time, anyone with access to the browser can use the account. That's convenient, but it creates risks:

  • Unattended computers: A staff member leaves their laptop unlocked at a café or in a shared office, and someone else sits down at a logged-in dashboard.
  • Shared devices: On a family computer, a library terminal, or a shop's point-of-sale machine, the next person inherits the session.
  • Stolen devices: A lost laptop or phone with an active session gives the finder direct access until the cookie expires.
  • Session hijacking: A stolen login cookie is useful to an attacker for as long as the session stays valid. Shorter sessions limit that window.
  • Compliance: Some industries and internal policies require automatic session timeouts for systems that handle personal or financial data.

Idle logout is especially valuable for administrator, shop manager, and editor accounts, which can make significant changes to your site.

Session Length vs Idle Timeout

These two terms are often mixed up, but they control different things:

  1. Session length (absolute timeout): How long a login lasts in total, no matter what the user does. WordPress sets this through the authentication cookie's expiry.
  2. Idle timeout (inactivity timeout): How long a user can be inactive before being logged out. Every time they do something, the timer resets.

WordPress core only has session length. It doesn't track inactivity at all. So if you want idle logout, you need a plugin or custom code. Many sites use both: an idle timeout of, say, 30 minutes, plus a maximum session length of 8 or 12 hours.

What WordPress Does When a Session Expires

When a session expires while you're in the dashboard, WordPress's built-in wp-auth-check feature notices through the Heartbeat API and shows a login popup over the current screen. You can log back in without leaving the page, and the block editor's autosave helps protect your content. This is useful to know, because it means a well-configured timeout doesn't have to destroy an editor's work.

Method 1: Use a Plugin

For most sites, a plugin is the simplest and most flexible option. Well-known choices include:

  • Inactive Logout: Logs out users after a set period of inactivity, shows a customisable warning popup with a countdown, and lets you set different timeouts per role in its premium version.
  • Idle User Logout: A simple plugin that logs users out after a configurable idle period, with options to exclude certain roles.
  • All-In-One Security (AIOS): Includes a "force logout" feature that logs users out after a fixed number of minutes. Note that this is an absolute timeout, not an idle one.

Here's how to set it up with Inactive Logout:

  1. Install the plugin: Go to Plugins > Add New Plugin, search for "Inactive Logout", then click Install Now and Activate.
  2. Open the settings: Go to Settings > Inactive Logout.
  3. Set the idle timeout: Enter the number of minutes of inactivity before logout. Between 15 and 30 minutes suits most admin teams.
  4. Configure the warning: Enable the countdown popup so users get a chance to click "Continue" before being logged out.
  5. Choose the redirect: Pick where users land after being logged out, such as the login page.
  6. Save and test: Log in on a test account, leave the tab idle, and confirm the warning and logout work as expected.

Choosing the Right Timeout

There's no single correct value. Think about who uses your site and how:

  • High-security admin areas: 10 to 15 minutes of inactivity.
  • Editorial teams: 30 to 60 minutes, so writers who pause to research don't get logged out constantly.
  • Customers on a store or membership site: Usually no idle logout, or a long one, since frequent logouts frustrate customers. Focus on admin roles instead.

If your plugin supports per-role settings, use shorter timeouts for administrators and longer ones for lower-privilege users.

Method 2: Shorten the Session Length With Code

Even if you use a plugin for idle logout, it's worth reducing WordPress's default session length. The auth_cookie_expiration filter controls how long the login cookie lasts. Add this to a custom plugin or your child theme's functions.php:

<?php
/**
 * Shorten WordPress session lengths.
 *
 * @param int  $length   Default length in seconds.
 * @param int  $user_id  User ID.
 * @param bool $remember Whether "Remember Me" was checked.
 * @return int
 */
function sajjad_session_length( $length, $user_id, $remember ) {
    // Administrators get shorter sessions, regardless of Remember Me.
    if ( user_can( $user_id, 'manage_options' ) ) {
        return 8 * HOUR_IN_SECONDS;
    }

    // Everyone else: 12 hours normally, 7 days with Remember Me.
    return $remember ? 7 * DAY_IN_SECONDS : 12 * HOUR_IN_SECONDS;
}
add_filter( 'auth_cookie_expiration', 'sajjad_session_length', 10, 3 );

This only applies to new logins. Users who are already logged in keep their existing session until it expires or they log out. To end all current sessions immediately, you can rotate your security keys and salts, or use the Log Out Everywhere Else button in a user's profile under Users > Profile.

Method 3: Build an Idle Logout With Code

If you want idle logout without a plugin, you can build it with a small must-use plugin. The approach below does two things:

  1. Server-side enforcement: It stores the last activity time in the user's WordPress session and logs them out on the next request if they've been idle too long. This works even if JavaScript is disabled.
  2. Client-side redirect: It adds a small script to the dashboard that logs the user out after the idle period, so an unattended screen doesn't stay open showing your admin area.

Create the file wp-content/mu-plugins/sajjad-idle-logout.php. Must-use plugins load automatically and can't be deactivated from the dashboard by accident. As always, take a backup and test on a staging site first.

<?php
/**
 * Plugin Name: Idle Logout
 * Description: Logs users out after a period of inactivity.
 * Version:     1.0.0
 * Author:      Sajjad
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// Idle timeout in seconds (30 minutes).
if ( ! defined( 'SAJJAD_IDLE_TIMEOUT' ) ) {
    define( 'SAJJAD_IDLE_TIMEOUT', 30 * MINUTE_IN_SECONDS );
}

/**
 * Check idle time on every request and update last activity.
 */
function sajjad_idle_check() {
    if ( ! is_user_logged_in() || wp_doing_cron() ) {
        return;
    }

    $user_id = get_current_user_id();
    $token   = wp_get_session_token();

    if ( '' === $token ) {
        return;
    }

    $manager = WP_Session_Tokens::get_instance( $user_id );
    $session = $manager->get( $token );

    if ( ! is_array( $session ) ) {
        return;
    }

    $now  = time();
    $last = isset( $session['sajjad_last_activity'] ) ? (int) $session['sajjad_last_activity'] : $now;

    // Idle for too long: end this session only.
    if ( ( $now - $last ) > SAJJAD_IDLE_TIMEOUT ) {
        wp_logout();

        if ( wp_doing_ajax() ) {
            wp_send_json_error( array( 'message' => 'Session expired due to inactivity.' ), 401 );
        }

        wp_safe_redirect( add_query_arg( 'idle', '1', wp_login_url() ) );
        exit;
    }

    // Heartbeat requests are automatic, so they don't count as activity.
    // phpcs:ignore WordPress.Security.NonceVerification.Missing
    $is_heartbeat = wp_doing_ajax() && isset( $_POST['action'] ) && 'heartbeat' === $_POST['action'];

    $first_request = ! isset( $session['sajjad_last_activity'] );
    $is_stale      = ( $now - $last ) > MINUTE_IN_SECONDS;

    // Record activity on the first request, then at most once a minute.
    if ( $first_request || ( ! $is_heartbeat && $is_stale ) ) {
        $session['sajjad_last_activity'] = $now;
        $manager->update( $token, $session );
    }
}
add_action( 'init', 'sajjad_idle_check', 1 );

/**
 * Show a friendly message on the login screen after an idle logout.
 */
function sajjad_idle_login_message( $message ) {
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    if ( isset( $_GET['idle'] ) ) {
        $message .= '<p class="message">' . esc_html__( 'You were logged out due to inactivity. Please log in again.', 'sajjad' ) . '</p>';
    }
    return $message;
}
add_filter( 'login_message', 'sajjad_idle_login_message' );

/**
 * Add a client-side idle timer to the dashboard.
 */
function sajjad_idle_admin_script() {
    $logout_url = add_query_arg(
        array(
            'action'      => 'logout',
            '_wpnonce'    => wp_create_nonce( 'log-out' ),
            'redirect_to' => rawurlencode( add_query_arg( 'idle', '1', wp_login_url() ) ),
        ),
        wp_login_url()
    );

    wp_register_script( 'sajjad-idle-logout', false, array(), '1.0.0', array( 'in_footer' => true ) );
    wp_enqueue_script( 'sajjad-idle-logout' );

    wp_add_inline_script(
        'sajjad-idle-logout',
        'window.sajjadIdle = ' . wp_json_encode(
            array(
                'timeout'   => SAJJAD_IDLE_TIMEOUT,
                'logoutUrl' => $logout_url,
            )
        ) . ';',
        'before'
    );

    wp_add_inline_script( 'sajjad-idle-logout', sajjad_idle_js() );
}
add_action( 'admin_enqueue_scripts', 'sajjad_idle_admin_script' );

/**
 * The idle timer JavaScript.
 */
function sajjad_idle_js() {
    return <<<'JS'
( function () {
    const settings = window.sajjadIdle;
    if ( ! settings ) {
        return;
    }

    const timeoutMs = settings.timeout * 1000;
    let timer;

    const reset = () => {
        clearTimeout( timer );
        timer = setTimeout( () => {
            window.location.href = settings.logoutUrl;
        }, timeoutMs );
    };

    [ 'mousemove', 'mousedown', 'keydown', 'scroll', 'touchstart' ].forEach( ( eventName ) => {
        document.addEventListener( eventName, reset, { passive: true } );
    } );

    reset();
} )();
JS;
}

How This Code Works

  • Per-session tracking: Instead of storing activity in user meta, which is shared across all of a user's devices, it uses WP_Session_Tokens to store the timestamp in the current session. Logging out one idle laptop doesn't affect the same user's active session on another device.
  • Heartbeat is ignored: The WordPress Heartbeat API sends requests in the background every 15 to 120 seconds while a dashboard tab is open. If those counted as activity, users would never time out. The code excludes them.
  • Throttled writes: It only updates the timestamp once a minute, so it doesn't write to the database on every page load.
  • The logout URL is built manually: wp_logout_url() returns an HTML-escaped URL, which isn't suitable for JavaScript. Building it with add_query_arg() and a log-out nonce avoids that problem.
  • Client-side timer: If the user doesn't move the mouse, type, or scroll for the idle period, the browser navigates to the logout URL.

One limitation to be aware of: the client-side timer only watches the current tab. If a user has two dashboard tabs open and is working in one, the other tab's timer may still fire. For teams that work across many tabs, a plugin with cross-tab syncing, or relying only on the server-side check, may suit you better.

Adjusting the Timeout

You can change the timeout without editing the plugin by defining the constant in wp-config.php, above the line that says /* That's all, stop editing! Happy publishing. */:

define( 'SAJJAD_IDLE_TIMEOUT', 15 * 60 ); // 15 minutes

Protecting Unsaved Work

The biggest complaint about idle logout is lost work. A few habits and settings help:

  • Autosave: The block editor autosaves drafts regularly and stores local backups in the browser. When a user logs back in, WordPress usually offers to restore the newer version.
  • Warning popups: If you use a plugin, enable the countdown warning so users can stay logged in with a single click.
  • Longer timeouts for writers: Give editorial roles a longer idle period than administrators.
  • Train your team: Encourage people to save drafts before stepping away, especially when writing long content.

Beyond Idle Logout

Idle logout works best alongside a few related practices:

  • Two-factor authentication: Makes it much harder for someone to log back in on a device they found or stole.
  • Session management: Under Users > Profile, the Log Out Everywhere Else button ends all other sessions for your account. Administrators can do the same for other users from their profile screens.
  • Security keys rotation: Rotating keys and salts ends every session on the site at once, which is useful after a security incident.
  • Device habits: Locking your screen when you step away protects everything, not just WordPress.

FAQ: Automatic Logout for Idle Users in WordPress

No. WordPress only has a fixed session length, which is two days by default or 14 days with Remember Me. It doesn't track inactivity, so you need a plugin or custom code for idle logout.

Between 15 and 30 minutes suits most admin teams. High-security sites may use 10 to 15 minutes, while editorial teams often prefer 30 to 60 minutes.

It can, but the block editor's autosave and local backups usually let users restore their drafts after logging back in. A warning popup before logout also helps.

Use the auth_cookie_expiration filter in a custom plugin or your child theme's functions.php to return a shorter number of seconds, as shown in this guide.

Heartbeat sends background requests while a dashboard tab is open. If your idle logic counts those as activity, the timer keeps resetting. Exclude heartbeat requests, as the code in this guide does.

Usually not, or only with a long timeout. Frequent logouts frustrate customers. Focus idle logout on administrators, shop managers, and editors instead.


Conclusion

Automatic logout for idle users closes a simple but real gap in WordPress: a logged-in browser that nobody is watching. The quickest route is a plugin like Inactive Logout, which gives you a timeout, a warning popup, and role-based options in a few clicks. If you prefer code, pair auth_cookie_expiration for shorter sessions with a small must-use plugin that tracks each session's last activity and ignores Heartbeat requests.

Whatever method you choose, pick timeouts that match how your team actually works, give people a warning before they're logged out, and lean on autosave to protect their drafts. Combined with two-factor authentication and good device habits, idle logout helps make sure a moment of inattention doesn't turn into a security incident.

Share :

Related Posts

What are the best WordPress security plugins?

What are the best WordPress security plugins?

The best WordPress security plugins for most sites are Wordfence, Sucuri Security, Solid Security, MalCare, All-In-One Security (AIOS), Patchstack, a

Dive Deeper
What are the most common website security threats?

What are the most common website security threats?

The most common website security threats are vulnerable or outdated software, weak and stolen passwords, malware infections, injection attacks like S

Dive Deeper
What is the difference between posts and pages in WordPress?

What is the difference between posts and pages in WordPress?

The main difference between posts and pages in WordPress is that posts are timely, dated entries that appear in your blog feed, archives, and RSS fee

Dive Deeper