Are IIR filters (and specifically Butterworth filter) causal? I am new to signal processing. I am learning now about filtering and I am trying to implement high pass filter (HPF),and later band-pass filter (BPF). I implement the filters in Python 3.8 with NumPy and SciPy.
For the offline case (filtering a pre-recorded time) I designed a Butterworth high-pass filter, and applied on the signal at the time domain using signal.filtfilt function. However, as the documentation shows, this approach is good only for offline cases and not for real-time, since the filter scans the signal forward and then backwards. I can recover the frequency response from the filter using signal.freqz function.
Now I want that this filter will work also in real-time (so it needs to be causal, and I ask if this possible for this type of filters. Here are my questions:

If I understand correctly, Butterworth filters are IIR (infinite impulse response) filters. Is it true?
Are IIR filter causal? It may be that all IIR filters are not causal and it may be that some are and some are not. What are the cases in which IIR filters are causal?
Are Butterworth filters causal? If not always, in which case they are causal?
If the answer to 3 is true, how to implement a causal Butterworth filter, both at the time domain and the frequency domain? (I can use SciPy functions such as signal.butter, signal.freqz etc.)

Relevant links:

Help designing Butterworth filter
filtfilt: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.filtfilt.html

Thank you.
Yes, Butterworth are IIR.  The decay from an impulse technically lasts forever.
Yes, all [implementable] IIR are causal.
Yes, because of #1 and #2.
Don't use signal.filtfilt.  Use signal.lfilter.  filtfilt does the same thing as lfilter, except twice, in opposite directions, which changes a causal filter into a zero-phase filter.

However, as the documentation for both of those functions suggests, for most practical use, you should actually use the SOS variants instead:

The function sosfilt (and filter design using output='sos') should be
preferred over lfilter for most filtering tasks, as second-order sections
have fewer numerical problems.

To summarize the functions:

lfilter: Causal single-stage filtering (low orders only)
filtfilt: Zero-phase single-stage filtering (low orders only)
sosfilt: Causal second-order sections filtering
sosfiltfilt: Zero-phase second-order sections filtering

Really the only reason to use lfilter or filtfilt is if your coefficients are already in b, a format, if you're implementing something out of a textbook, etc.
If you're designing the filter yourself, then just use SOS form, which reduces numerical error.
Note that the filtfilt functions apply the filter twice, so it will have double the order of the original filter.