Using the fingerprint() method in this contract:

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

contract Fingerprint {
    function fingerprint() public view returns (address,address,uint,uint,uint,bytes32,uint) {
        return (
            msg.sender, 
            tx.origin,
            tx.gasprice, 
            gasleft(),
            block.number, 
            blockhash(block.number - 1),
            block.timestamp);
    }
}

Evaluated in different contexts:

Remix (JS VM) Remix (testnet) Etherscan ethers + infura ethers + alchemy
msg.sender builtin addr connected addr 0x0 0x0 0x0
tx.origin builtin addr connected addr 0x0 0x0 0x0
tx.gasprice 1 0 0 0 0
gasleft() 2978728 2978794 99978666 499978794 549978794
block.number 1 real (6380005) real real real
blockhash H1 real real real real
block.ts 1644870999 1644877262 real real real

Based on this table, we could use this crude off-chain evaluation mechanism:

function isEvaluatedOffchain() public view returns (bool) {
        return tx.origin == address(0)
            || tx.gasprice <= 1
            || gasleft() > 30_000_000;
}

Testing it:

/// fingerprint.mjs

import {ethers} from "ethers";

const provider = new ethers.providers.JsonRpcProvider('<https://eth-goerli.alchemyapi.io/v2/-dTf2BzzoSXZ0k_DAjwcNSXcOFpidhxA>');

const humanReadableAbi = [
    "function fingerprint() public view returns (address,address,uint,uint,uint,bytes32,uint)",
    "function isEvaluatedOffchain() public view returns (bool)",
];

const Fingerprint = new ethers.Contract("0xDC4DcA57c94Fc4aB8483f708B24e2D36E5dB36bf", humanReadableAbi, provider);

Fingerprint.fingerprint({
	gasLimit:500000,
	maxFeePerGas: 59000000000,
	from: "0x8830c393b2ed864Bb3c1A2FB9Fce8dA83f6db66c"
}).then(console.log);

const naiveEval = await Fingerprint.isEvaluatedOffchain();
// => true

const fancyEval = await Fingerprint.isEvaluatedOffchain({
	gasLimit:500000,
	maxFeePerGas: 59000000000,
	from: "0x8830c393b2ed864Bb3c1A2FB9Fce8dA83f6db66c"
});
// => false

console.log("isEvaluatedOffchain with naive evaluation?", naiveEval);
console.log("isEvaluatedOffchain with fancy evaluation?", fancyEval);

https://github.com/Vectorized/solady/pull/876

contract to check the values:

https://holesky.etherscan.io/address/0x881edfb1cd148894fd50542d77fda8004d5c8056#readContract