Yes, token-transfer always has a value of 0 (as the value attribute is associated with Ether), but the data part will have some value when doing a token transfer. I have worked on this topic recently, I myself wanted to know the same. To understand it much better I had to filter some transactions and check myself how does an ETH transaction differ from token transfer. All the below transactions are taken from TESTNET:

ETH TRANSFER

Transaction Hash: 0x27c3fe1bc90723e5d7e0dbc3429e71faa967a623c8e4c49df0739283c17718e6

Transaction log:

> web3.eth.getTransaction("0x27c3fe1bc90723e5d7e0dbc3429e71faa967a623c8e4c49df0739283c17718e6"); { blockHash: '0x06111bf75fb9108dc5596ddbb6e2e843ee13830987688a90df2ab0772815fa96', blockNumber: 1488295, from: '0x76e0bb92b6f8d431af2fe1bafd304eb832241619', gas: 21000, gasPrice: { [String: '31000000000'] s: 1, e: 10, c: [ 31000000000 ] }, hash: '0x27c3fe1bc90723e5d7e0dbc3429e71faa967a623c8e4c49df0739283c17718e6', input: '0x', nonce: 261, to: '0xb1aa0ac057639e534a89b095853befc4d6d264cf', transactionIndex: 0, value: { [String: '1000000000000000000'] s: 1, e: 18, c: [ 10000 ] }, v: '0x2a', r: '0x3b4202fda27b6fdfb6985e10ffcd7b5f9f2a64e31fc75d444d6a7684a75f3b', s: '0x5bb67429e6cae209f53ad5c1538d0c3d0035f12e92a569c0b2898512d9cdeae5' }

Transaction Receipt:

> web3.eth.getTransactionReceipt("0x27c3fe1bc90723e5d7e0dbc3429e71faa967a623c8e4c49df0739283c17718e6"); { blockHash: '0x06111bf75fb9108dc5596ddbb6e2e843ee13830987688a90df2ab0772815fa96', blockNumber: 1488295, contractAddress: null, cumulativeGasUsed: 21000, from: '0x76e0bb92b6f8d431af2fe1bafd304eb832241619', gasUsed: 21000, logs: [], logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', root: '0x6a29376fb5c83a4617fecc1b95c1353f37711912128fd3b6bce9dde57b8130b3', to: '0xb1aa0ac057639e534a89b095853befc4d6d264cf', transactionHash: '0x27c3fe1bc90723e5d7e0dbc3429e71faa967a623c8e4c49df0739283c17718e6', transactionIndex: 0 }

If you carefully check the above logs, the value property in the Transaction Log has the value of 1000000000000000000 wei i.e. 1 Ether. and the Input is 0x

Similarly the Logs in the Transaction Receipt is an empty object. Which will not be empty when a token transfer happens.

TOKEN TRANSFER

Ropesten Transaction Details: 0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677

Transaction Log

web3.eth.getTransaction("0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677"); { blockHash: '0x34ee516310a59407712455ec87bd76046a1e68f5c631dc8e6b4bb903b8c92834', blockNumber: 1535104, from: '0x76e0bb92b6f8d431af2fe1bafd304eb832241619', gas: 223616, gasPrice: { [String: '22000000000'] s: 1, e: 10, c: [ 22000000000 ] }, hash: '0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677', input: '0xa9059cbb0000000000000000000000002b3425ce986f9f0f599758f4fb33158ca671e83e0000000000000000000000000000000000000000000000000000000000000001', nonce: 267, to: '0x5c99dadde01ce61ab5b5536d566bf41ecd17e3a9', transactionIndex: 7, value: { [String: '0'] s: 1, e: 0, c: [ 0 ] }, v: '0x1b', r: '0x4ad36e9eefd233abce864b3e53b86d1b937bcea83223564e4f56cc7defbcde3e', s: '0x22f256f9fe62187dc0e8942981ef52ae3643d04f50e00957c94e10b8da4e3116' }

If you check the above transaction Log, it clearly suggests that this transaction was a Token Transfer, as the below properties help us:

- Input: '0xa9059cbb0000000000000000000000002b3425ce986f9f0f599758f4fb33158ca671e83e0000000000000000000000000000000000000000000000000000000000000001'

0xa9059cbb is the hex for transfer. 0000000000000000000000002b3425ce986f9f0f599758f4fb33158ca671e83e is the address to which the token was sent with left padding upto 64 places 0000000000000000000000000000000000000000000000000000000000000001 is the number of tokens to be sent left padded upto 64 places.

value property is 0x0 (this shows no ether were sent)

Transaction Receipt

web3.eth.getTransactionReceipt("0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677"); { blockHash: '0x34ee516310a59407712455ec87bd76046a1e68f5c631dc8e6b4bb903b8c92834', blockNumber: 1535104, contractAddress: null, cumulativeGasUsed: 352435, from: '0x76e0bb92b6f8d431af2fe1bafd304eb832241619', gasUsed: 36979, logs: [ { address: '0x5c99dadde01ce61ab5b5536d566bf41ecd17e3a9', topics: [Object], data: '0x0000000000000000000000000000000000000000000000000000000000000001', blockNumber: 1535104, transactionHash: '0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677', transactionIndex: 7, blockHash: '0x34ee516310a59407712455ec87bd76046a1e68f5c631dc8e6b4bb903b8c92834', logIndex: 6, removed: false } ], logsBloom: '0x00000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000400000000000000000000000000000004000000000000000000000000000000400000000000000000001000000000000000000002000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000', root: '0x9840ddaa4571522013623410420a11689fc44184d52d541d4f1067adcdde9e8c', to: '0x5c99dadde01ce61ab5b5536d566bf41ecd17e3a9', transactionHash: '0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677', transactionIndex: 7 }

As I said earlier, the logs property when a ETH trasnfer happens is empty but when a token transfer happens logs property has an object which helps in identifying to/from which address the token got transferred. the data property helps in knowing the amount of tokens transferred.

address:'0x5c99dadde01ce61ab5b5536d566bf41ecd17e3a9', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x00000000000000000000000076e0bb92b6f8d431af2fe1bafd304eb832241619', '0x0000000000000000000000002b3425ce986f9f0f599758f4fb33158ca671e83e' ], data: '0x0000000000000000000000000000000000000000000000000000000000000001', blockNumber: 1535104, transactionHash: '0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677', transactionIndex: 7, blockHash: '0x34ee516310a59407712455ec87bd76046a1e68f5c631dc8e6b4bb903b8c92834', logIndex: 6, removed: false } ]

If I remember it correctly,to distinguish much more clearly between transactions, you can try using the a logParser made using SolidityEvent Library which can be found inside web3.js. Here is the link to the same.