Recherche avancée

Médias (1)

Mot : - Tags -/belgique

Autres articles (85)

  • Mediabox : ouvrir les images dans l’espace maximal pour l’utilisateur

    8 février 2011, par

    La visualisation des images est restreinte par la largeur accordée par le design du site (dépendant du thème utilisé). Elles sont donc visibles sous un format réduit. Afin de profiter de l’ensemble de la place disponible sur l’écran de l’utilisateur, il est possible d’ajouter une fonctionnalité d’affichage de l’image dans une boite multimedia apparaissant au dessus du reste du contenu.
    Pour ce faire il est nécessaire d’installer le plugin "Mediabox".
    Configuration de la boite multimédia
    Dès (...)

  • Les autorisations surchargées par les plugins

    27 avril 2010, par

    Mediaspip core
    autoriser_auteur_modifier() afin que les visiteurs soient capables de modifier leurs informations sur la page d’auteurs

  • D’autres logiciels intéressants

    12 avril 2011, par

    On ne revendique pas d’être les seuls à faire ce que l’on fait ... et on ne revendique surtout pas d’être les meilleurs non plus ... Ce que l’on fait, on essaie juste de le faire bien, et de mieux en mieux...
    La liste suivante correspond à des logiciels qui tendent peu ou prou à faire comme MediaSPIP ou que MediaSPIP tente peu ou prou à faire pareil, peu importe ...
    On ne les connais pas, on ne les a pas essayé, mais vous pouvez peut être y jeter un coup d’oeil.
    Videopress
    Site Internet : (...)

Sur d’autres sites (6024)

  • VLC dead input for RTP stream

    27 mars, par CaptainCheese

    I'm working on creating an rtp stream that's meant to display live waveform data from Pioneer prolink players. The motivation for sending this video out is to be able to receive it in a flutter frontend. I initially was just sending a base-24 encoding of the raw ARGB packed ints per frame across a Kafka topic to it but processing this data in flutter proved to be untenable and was bogging down the main UI thread. Not sure if this is the most optimal way of going about this but just trying to get anything to work if it means some speedup on the frontend. So the issue the following implementation is experiencing is that when I run vlc --rtsp-timeout=120000 --network-caching=30000 -vvvv stream_1.sdp where

    


    % cat stream_1.sdp
v=0
o=- 0 1 IN IP4 127.0.0.1
s=RTP Stream
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat
m=video 5007 RTP/AVP 96
a=rtpmap:96 H264/90000


    


    I see (among other questionable logs) the following :

    


    [0000000144c44d10] live555 demux error: no data received in 10s, aborting
[00000001430ee2f0] main input debug: EOF reached
[0000000144b160c0] main decoder debug: killing decoder fourcc `h264'
[0000000144b160c0] main decoder debug: removing module "videotoolbox"
[0000000144b164a0] main packetizer debug: removing module "h264"
[0000000144c44d10] main demux debug: removing module "live555"
[0000000144c45bb0] main stream debug: removing module "record"
[0000000144a64960] main stream debug: removing module "cache_read"
[0000000144c29c00] main stream debug: removing module "filesystem"
[00000001430ee2f0] main input debug: Program doesn't contain anymore ES
[0000000144806260] main playlist debug: dead input
[0000000144806260] main playlist debug: changing item without a request (current 0/1)
[0000000144806260] main playlist debug: nothing to play
[0000000142e083c0] macosx interface debug: Playback has been ended
[0000000142e083c0] macosx interface debug: Releasing IOKit system sleep blocker (37463)


    


    This is sort of confusing because when I run ffmpeg -protocol_whitelist file,crypto,data,rtp,udp -i stream_1.sdp -vcodec libx264 -f null -
I see a number logs about

    


    [h264 @ 0x139304080] non-existing PPS 0 referenced
    Last message repeated 1 times
[h264 @ 0x139304080] decode_slice_header error
[h264 @ 0x139304080] no frame!


    


    After which I see the stream is received and I start getting telemetry on it :

    


    Input #0, sdp, from 'stream_1.sdp':
  Metadata:
    title           : RTP Stream
  Duration: N/A, start: 0.016667, bitrate: N/A
  Stream #0:0: Video: h264 (Constrained Baseline), yuv420p(progressive), 1200x200, 60 fps, 60 tbr, 90k tbn
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
Press [q] to stop, [?] for help
[libx264 @ 0x107f04f40] using cpu capabilities: ARMv8 NEON
[libx264 @ 0x107f04f40] profile High, level 3.1, 4:2:0, 8-bit
Output #0, null, to 'pipe:':
  Metadata:
    title           : RTP Stream
    encoder         : Lavf61.7.100
  Stream #0:0: Video: h264, yuv420p(tv, progressive), 1200x200, q=2-31, 60 fps, 60 tbn
      Metadata:
        encoder         : Lavc61.19.101 libx264
      Side data:
        cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
[out#0/null @ 0x60000069c000] video:144KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
frame= 1404 fps= 49 q=-1.0 Lsize=N/A time=00:00:23.88 bitrate=N/A speed=0.834x


    


    Not sure why VLC is turning me down like some kind of Berghain bouncer that lets nobody in the entire night.

    


    I initially tried just converting the ARGB ints to a YUV420p buffer and used this to create the Frame objects but I couldn't for the life of me figure out how to properly initialize it as the attempts I made kept spitting out garbled junk.

    


    Please go easy on me, I've made an unhealthy habit of resolving nearly all of my coding questions by simply lurking the internet for answers but that's not really helping me solve this issue.

    


    Here's the Java I'm working on (the meat of the rtp comms occurs within updateWaveformForPlayer()) :

    


    package com.bugbytz.prolink;&#xA;&#xA;import org.apache.kafka.clients.producer.KafkaProducer;&#xA;import org.apache.kafka.clients.producer.Producer;&#xA;import org.apache.kafka.clients.producer.ProducerConfig;&#xA;import org.apache.kafka.clients.producer.ProducerRecord;&#xA;import org.bytedeco.ffmpeg.global.avcodec;&#xA;import org.bytedeco.ffmpeg.global.avutil;&#xA;import org.bytedeco.javacv.FFmpegFrameGrabber;&#xA;import org.bytedeco.javacv.FFmpegFrameRecorder;&#xA;import org.bytedeco.javacv.FFmpegLogCallback;&#xA;import org.bytedeco.javacv.Frame;&#xA;import org.bytedeco.javacv.FrameGrabber;&#xA;import org.deepsymmetry.beatlink.CdjStatus;&#xA;import org.deepsymmetry.beatlink.DeviceAnnouncement;&#xA;import org.deepsymmetry.beatlink.DeviceAnnouncementAdapter;&#xA;import org.deepsymmetry.beatlink.DeviceFinder;&#xA;import org.deepsymmetry.beatlink.Util;&#xA;import org.deepsymmetry.beatlink.VirtualCdj;&#xA;import org.deepsymmetry.beatlink.data.BeatGridFinder;&#xA;import org.deepsymmetry.beatlink.data.CrateDigger;&#xA;import org.deepsymmetry.beatlink.data.MetadataFinder;&#xA;import org.deepsymmetry.beatlink.data.TimeFinder;&#xA;import org.deepsymmetry.beatlink.data.WaveformDetail;&#xA;import org.deepsymmetry.beatlink.data.WaveformDetailComponent;&#xA;import org.deepsymmetry.beatlink.data.WaveformFinder;&#xA;&#xA;import java.awt.*;&#xA;import java.awt.image.BufferedImage;&#xA;import java.io.File;&#xA;import java.nio.ByteBuffer;&#xA;import java.text.DecimalFormat;&#xA;import java.util.ArrayList;&#xA;import java.util.HashMap;&#xA;import java.util.HashSet;&#xA;import java.util.Map;&#xA;import java.util.Properties;&#xA;import java.util.Set;&#xA;import java.util.concurrent.ExecutionException;&#xA;import java.util.concurrent.Executors;&#xA;import java.util.concurrent.ScheduledExecutorService;&#xA;import java.util.concurrent.ScheduledFuture;&#xA;import java.util.concurrent.TimeUnit;&#xA;&#xA;import static org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_RGB24;&#xA;&#xA;public class App {&#xA;    public static ArrayList<track> tracks = new ArrayList&lt;>();&#xA;    public static boolean dbRead = false;&#xA;    public static Properties props = new Properties();&#xA;    private static Map recorders = new HashMap&lt;>();&#xA;    private static Map frameCount = new HashMap&lt;>();&#xA;&#xA;    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);&#xA;    private static final int FPS = 60;&#xA;    private static final int FRAME_INTERVAL_MS = 1000 / FPS;&#xA;&#xA;    private static Map schedules = new HashMap&lt;>();&#xA;&#xA;    private static Set<integer> streamingPlayers = new HashSet&lt;>();&#xA;&#xA;    public static String byteArrayToMacString(byte[] macBytes) {&#xA;        StringBuilder sb = new StringBuilder();&#xA;        for (int i = 0; i &lt; macBytes.length; i&#x2B;&#x2B;) {&#xA;            sb.append(String.format("%02X%s", macBytes[i], (i &lt; macBytes.length - 1) ? ":" : ""));&#xA;        }&#xA;        return sb.toString();&#xA;    }&#xA;&#xA;    private static void updateWaveformForPlayer(int player) throws Exception {&#xA;        Integer frame_for_player = frameCount.get(player);&#xA;        if (frame_for_player == null) {&#xA;            frame_for_player = 0;&#xA;            frameCount.putIfAbsent(player, frame_for_player);&#xA;        }&#xA;&#xA;        if (!WaveformFinder.getInstance().isRunning()) {&#xA;            WaveformFinder.getInstance().start();&#xA;        }&#xA;        WaveformDetail detail = WaveformFinder.getInstance().getLatestDetailFor(player);&#xA;&#xA;        if (detail != null) {&#xA;            WaveformDetailComponent component = (WaveformDetailComponent) detail.createViewComponent(&#xA;                    MetadataFinder.getInstance().getLatestMetadataFor(player),&#xA;                    BeatGridFinder.getInstance().getLatestBeatGridFor(player)&#xA;            );&#xA;            component.setMonitoredPlayer(player);&#xA;            component.setPlaybackState(player, TimeFinder.getInstance().getTimeFor(player), true);&#xA;            component.setAutoScroll(true);&#xA;            int width = 1200;&#xA;            int height = 200;&#xA;            Dimension dimension = new Dimension(width, height);&#xA;            component.setPreferredSize(dimension);&#xA;            component.setSize(dimension);&#xA;            component.setScale(1);&#xA;            component.doLayout();&#xA;&#xA;            // Create a fresh BufferedImage and clear it before rendering&#xA;            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);&#xA;            Graphics2D g = image.createGraphics();&#xA;            g.clearRect(0, 0, width, height);  // Clear any old content&#xA;&#xA;            // Draw waveform into the BufferedImage&#xA;            component.paint(g);&#xA;            g.dispose();&#xA;&#xA;            int port = 5004 &#x2B; player;&#xA;            String inputFile = port &#x2B; "_" &#x2B; frame_for_player &#x2B; ".mp4";&#xA;            // Initialize the FFmpegFrameRecorder for YUV420P&#xA;            FFmpegFrameRecorder recorder_file = new FFmpegFrameRecorder(inputFile, width, height);&#xA;            FFmpegLogCallback.set();  // Enable FFmpeg logging for debugging&#xA;            recorder_file.setFormat("mp4");&#xA;            recorder_file.setVideoCodec(avcodec.AV_CODEC_ID_H264);&#xA;            recorder_file.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);  // Use YUV420P format directly&#xA;            recorder_file.setFrameRate(FPS);&#xA;&#xA;            // Set video options&#xA;            recorder_file.setVideoOption("preset", "ultrafast");&#xA;            recorder_file.setVideoOption("tune", "zerolatency");&#xA;            recorder_file.setVideoOption("x264-params", "repeat-headers=1");&#xA;            recorder_file.setGopSize(FPS);&#xA;            try {&#xA;                recorder_file.start();  // Ensure this is called before recording any frames&#xA;                System.out.println("Recorder started successfully for player: " &#x2B; player);&#xA;            } catch (org.bytedeco.javacv.FFmpegFrameRecorder.Exception e) {&#xA;                e.printStackTrace();&#xA;            }&#xA;&#xA;            // Get all pixels in one call&#xA;            int[] pixels = new int[width * height];&#xA;            image.getRGB(0, 0, width, height, pixels, 0, width);&#xA;            recorder_file.recordImage(width,height,Frame.DEPTH_UBYTE,1,3 * width, AV_PIX_FMT_RGB24, ByteBuffer.wrap(argbToByteArray(pixels, width, height)));&#xA;            recorder_file.stop();&#xA;            recorder_file.release();&#xA;            final FFmpegFrameRecorder recorder = recorders.get(player);&#xA;            FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);&#xA;&#xA;&#xA;            try {&#xA;                grabber.start();&#xA;            } catch (Exception e) {&#xA;                e.printStackTrace();&#xA;            }&#xA;            if (recorder == null) {&#xA;                try {&#xA;                    String outputStream = "rtp://127.0.0.1:" &#x2B; port;&#xA;                    FFmpegFrameRecorder initial_recorder = new FFmpegFrameRecorder(outputStream, grabber.getImageWidth(), grabber.getImageHeight());&#xA;                    initial_recorder.setFormat("rtp");&#xA;                    initial_recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);&#xA;                    initial_recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);&#xA;                    initial_recorder.setFrameRate(grabber.getFrameRate());&#xA;                    initial_recorder.setGopSize(FPS);&#xA;                    initial_recorder.setVideoOption("x264-params", "keyint=60");&#xA;                    initial_recorder.setVideoOption("rtsp_transport", "tcp");&#xA;                    initial_recorder.start();&#xA;                    recorders.putIfAbsent(player, initial_recorder);&#xA;                    frameCount.putIfAbsent(player, 0);&#xA;                    putToRTP(player, grabber, initial_recorder);&#xA;                }&#xA;                catch (Exception e) {&#xA;                    e.printStackTrace();&#xA;                }&#xA;            }&#xA;            else {&#xA;                putToRTP(player, grabber, recorder);&#xA;            }&#xA;            File file = new File(inputFile);&#xA;            if (file.exists() &amp;&amp; file.delete()) {&#xA;                System.out.println("Successfully deleted file: " &#x2B; inputFile);&#xA;            } else {&#xA;                System.out.println("Failed to delete file: " &#x2B; inputFile);&#xA;            }&#xA;        }&#xA;    }&#xA;&#xA;    public static void putToRTP(int player, FFmpegFrameGrabber grabber, FFmpegFrameRecorder recorder) throws FrameGrabber.Exception {&#xA;        final Frame frame = grabber.grabFrame();&#xA;        int frameCount_local = frameCount.get(player);&#xA;        frame.keyFrame = frameCount_local&#x2B;&#x2B; % FPS == 0;&#xA;        frameCount.put(player, frameCount_local);&#xA;        try {&#xA;            recorder.record(frame);&#xA;        } catch (FFmpegFrameRecorder.Exception e) {&#xA;            throw new RuntimeException(e);&#xA;        }&#xA;    }&#xA;    public static byte[] argbToByteArray(int[] argb, int width, int height) {&#xA;        int totalPixels = width * height;&#xA;        byte[] byteArray = new byte[totalPixels * 3];  // 4 bytes per pixel (ARGB)&#xA;&#xA;        for (int i = 0; i &lt; totalPixels; i&#x2B;&#x2B;) {&#xA;            int argbPixel = argb[i];&#xA;&#xA;            byteArray[i * 3] = (byte) ((argbPixel >> 16) &amp; 0xFF);  // Red&#xA;            byteArray[i * 3 &#x2B; 1] = (byte) ((argbPixel >> 8) &amp; 0xFF);   // Green&#xA;            byteArray[i * 3 &#x2B; 2] = (byte) (argbPixel &amp; 0xFF);  // Blue&#xA;        }&#xA;&#xA;        return byteArray;&#xA;    }&#xA;&#xA;&#xA;    public static void main(String[] args) throws Exception {&#xA;        VirtualCdj.getInstance().setDeviceNumber((byte) 4);&#xA;        CrateDigger.getInstance().addDatabaseListener(new DBService());&#xA;        props.put("bootstrap.servers", "localhost:9092");&#xA;        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");&#xA;        props.put("value.serializer", "com.bugbytz.prolink.CustomSerializer");&#xA;        props.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG, "20971520");&#xA;&#xA;        VirtualCdj.getInstance().addUpdateListener(update -> {&#xA;            if (update instanceof CdjStatus) {&#xA;                try (Producer producer = new KafkaProducer&lt;>(props)) {&#xA;                    DecimalFormat df_obj = new DecimalFormat("#.##");&#xA;                    DeviceStatus deviceStatus = new DeviceStatus(&#xA;                            update.getDeviceNumber(),&#xA;                            ((CdjStatus) update).isPlaying() || !((CdjStatus) update).isPaused(),&#xA;                            ((CdjStatus) update).getBeatNumber(),&#xA;                            update.getBeatWithinBar(),&#xA;                            Double.parseDouble(df_obj.format(update.getEffectiveTempo())),&#xA;                            Double.parseDouble(df_obj.format(Util.pitchToPercentage(update.getPitch()))),&#xA;                            update.getAddress().getHostAddress(),&#xA;                            byteArrayToMacString(DeviceFinder.getInstance().getLatestAnnouncementFrom(update.getDeviceNumber()).getHardwareAddress()),&#xA;                            ((CdjStatus) update).getRekordboxId(),&#xA;                            update.getDeviceName()&#xA;                    );&#xA;                    ProducerRecord record = new ProducerRecord&lt;>("device-status", "device-" &#x2B; update.getDeviceNumber(), deviceStatus);&#xA;                    try {&#xA;                        producer.send(record).get();&#xA;                    } catch (InterruptedException ex) {&#xA;                        throw new RuntimeException(ex);&#xA;                    } catch (ExecutionException ex) {&#xA;                        throw new RuntimeException(ex);&#xA;                    }&#xA;                    producer.flush();&#xA;                    if (!WaveformFinder.getInstance().isRunning()) {&#xA;                        try {&#xA;                            WaveformFinder.getInstance().start();&#xA;                        } catch (Exception ex) {&#xA;                            throw new RuntimeException(ex);&#xA;                        }&#xA;                    }&#xA;                }&#xA;            }&#xA;        });&#xA;        DeviceFinder.getInstance().addDeviceAnnouncementListener(new DeviceAnnouncementAdapter() {&#xA;            @Override&#xA;            public void deviceFound(DeviceAnnouncement announcement) {&#xA;                if (!streamingPlayers.contains(announcement.getDeviceNumber())) {&#xA;                    streamingPlayers.add(announcement.getDeviceNumber());&#xA;                    schedules.putIfAbsent(announcement.getDeviceNumber(), scheduler.scheduleAtFixedRate(() -> {&#xA;                        try {&#xA;                            Runnable task = () -> {&#xA;                                try {&#xA;                                    updateWaveformForPlayer(announcement.getDeviceNumber());&#xA;                                } catch (InterruptedException e) {&#xA;                                    System.out.println("Thread interrupted");&#xA;                                } catch (Exception e) {&#xA;                                    throw new RuntimeException(e);&#xA;                                }&#xA;                                System.out.println("Lambda thread work completed!");&#xA;                            };&#xA;                            task.run();&#xA;                        } catch (Exception e) {&#xA;                            e.printStackTrace();&#xA;                        }&#xA;                    }, 0, FRAME_INTERVAL_MS, TimeUnit.MILLISECONDS));&#xA;                }&#xA;            }&#xA;&#xA;            @Override&#xA;            public void deviceLost(DeviceAnnouncement announcement) {&#xA;                if (streamingPlayers.contains(announcement.getDeviceNumber())) {&#xA;                    schedules.get(announcement.getDeviceNumber()).cancel(true);&#xA;                    streamingPlayers.remove(announcement.getDeviceNumber());&#xA;                }&#xA;            }&#xA;        });&#xA;        BeatGridFinder.getInstance().start();&#xA;        MetadataFinder.getInstance().start();&#xA;        VirtualCdj.getInstance().start();&#xA;        TimeFinder.getInstance().start();&#xA;        DeviceFinder.getInstance().start();&#xA;        CrateDigger.getInstance().start();&#xA;&#xA;        try {&#xA;            LoadCommandConsumer consumer = new LoadCommandConsumer("localhost:9092", "load-command-group");&#xA;            Thread consumerThread = new Thread(consumer::startConsuming);&#xA;            consumerThread.start();&#xA;&#xA;            Runtime.getRuntime().addShutdownHook(new Thread(() -> {&#xA;                consumer.shutdown();&#xA;                try {&#xA;                    consumerThread.join();&#xA;                } catch (InterruptedException e) {&#xA;                    Thread.currentThread().interrupt();&#xA;                }&#xA;            }));&#xA;            Thread.sleep(60000);&#xA;        } catch (InterruptedException e) {&#xA;            System.out.println("Interrupted, exiting.");&#xA;        }&#xA;    }&#xA;}&#xA;</integer></track>

    &#xA;

  • The Ultimate Guide to HeatMap Software

    20 septembre 2021, par Ben Erskine — Analytics Tips, Plugins, Heatmaps

    One of the most effective ways to improve the user experience on your website is to use heatmap software. As well as in-depth insight on how to improve your website and funnels, user behaviour analytics complement traditional web metrics with insights from your customers’ point of view. 

    Heatmap software shows actual user behaviour. That means that you have a visual representation of why a customer might not be converting instead of guessing. 

    By tracking clicks, mouse movement, and page scrolling as well as analysing above the fold content engagement and overall session recordings, heatmap software helps improve user experience and therefore customer retention and conversions.  

    Matomo Heatmaps - Hotjar alternative

    What is heatmap software ?

    Heatmap software is a data visualisation tool that uses colour to show what actions a user is taking on a website. 

    If there is a design element on a page that many users engage with, it will show as red/hot. For elements that are less engaging, it will show on the analysis as blue/cold. 
     
    Heatmap software like Matomo helps businesses to improve user experience and increase conversions by tracking elements such as :
    Using data visualisation software like a heatmap provides more in-depth data when combined with standard website metrics. 

    What is heatmap software used for ?

    Heatmap software tracks website user behaviour to improve website performance and increase conversions. 

    Heatmaps can show you a detailed analysis of : 

    • Where visitors are clicking (or not clicking) 
    • Where visitors are hovering with their mouse
    • How far users are scrolling or stopping 
    • Where the focus is above the fold 
    • What roadblocks or frictions customers are facing in the sales funnel

    Analysing activity on your website and across channels from your customers point of view is critical in developing a customer-centric business model. 

    This is because heatmaps not only show you what customers are doing but why they are doing it. 

    Heatmap software is ideal for businesses updating and redesigning websites. It also helps to answer important growth questions such as “how can we improve our user experience ?” and “why is our sales funnel not converting better ?”. 

    The benefits of using data visualisation like heatmaps for your website

    Heatmaps are critical for improving websites because they drastically improve customer experience. 

    Customer experience is one of the most important factors in modern business success. A Walker study found that customer experience is one of the biggest differentiators between brands, overtaking other factors such as price. 

    Where straightforward website metrics show customers left a page without action, data visualisation and session recordings show what happens in between them arriving and leaving. This gives web developers and marketers invaluable insights to improve website design and ultimately increase conversions. 

    How heatmap software improves your website and conversions

    There are a few key ways that heatmap software boosts website performance and conversions. All of them focus on both creating a seamless buyer journey and using data to improve results over time. 

    How heatmap software improves conversions ; 

    • By improving UX and usability70% of online businesses fail due to bad usability. Heatmaps identify user frustrations and optimise accordingly 
    • By improving content structure – Heatmaps take the guesswork out of design layout and content structure by showing real visitor experiences on your website 
    • By comparing A/B landing pages – Using heatmaps on alternate landing pages can show you why conversions are working or not working based on user activity on the page
    • By optimising across devices – See how your visitors are interacting with your content to learn how well optimised your website is for various devices and remove roadblocks 

    Heatmap analytics you need to improve website user experience

    Click heatmap

    Click heatmaps are useful for two key reasons.

    Firstly, it shows where website users are clicking. 

    Heatmaps that show clicks give you a visual representation of whether copy and CTA links are clear from the customers’ point of view. It can also show whether a customer is clicking on a design feature that doesn’t link anywhere. 

    Secondly, it shows where website users are not clicking. This is just as important when developing funnels and improving user experiences.

    For example, you may have a CTA button for a free trial or purchase. A click heatmap analysis would show if this isn’t clicked on mobile devices and informs developers that it needs to be more mobile-friendly.

    Mouse move or hover heatmap

    Like a click heatmap, a mouse hover heatmap shows how you can improve the overall user experience.

    For example, hover heatmaps identify where your visitors engage on a particular webpage. Ideally, of course, you want them to engage with CTAs. Analysing their mouse movements or where they are hovering for more information gives you an indication of any page elements that are distracting them or not working.

    Matomo's heatmaps feature

    Scroll heatmap

    scroll heatmap uses colours to visualise how far down in a page your visitors scroll. For most web pages, the top will have the most impressions and will naturally get less views (i.e. get “colder” on the heatmap) further down the page. 

    This lets you find out if there is important content positioned too far down the page or if the page is designed to encourage users to keep scrolling.

    No matter how good your product or service is, it won’t convert if potential customers aren’t engaged and scrolling far enough to see it.

    Above the fold analysis 

    Above the fold is the content that a visitor sees without scrolling. 

    In a heatmap, the “Average Above the Fold” line will show you how much content your visitors see on average when they open your page. It also shows whether the page design is engaging, whether it encourages visitors to keep scrolling, and whether important information is too far down the page and therefore being missed. 

    Above the fold analysis is arguably the most important as this is the section that the highest number of traffic will see. Using this information ensures that the right content for conversion is seen by the highest number of visitors. 

    Session recording

    Session Recording lets you record a real visitor session, so you can see clicks, mouse movements, scrolls, window resizes, page changes, and form interactions all in one. 

    They allow you to understand the experience from the point of view of your visitor and then optimise your website to maximise your success.

    Heatmap software like Matomo takes this one step further and allows you to gather session recordings for individual segments. By analysing sessions based on segments, you can further personalise and optimise based on customer history and patterns.

    Final thoughts on heatmap software 

    Heatmap software improves your user experience by easily spotting critical issues that you can then address. 

    As well as that, heatmap analytics like clicks, mouse movement, scroll, above the fold analysis and session recordings increase your marketing ROI by making the most of your existing traffic. 

    It’s a win-win ! 

    Now that you know what heatmap software is, the benefits of using heatmaps on your website and how it can improve your user experience, check out this user guide on heatmap analytics

  • 4 ways to create more effective funnels

    24 février 2020, par Jake Thornton — Uncategorized

    Accurately measuring the success of your customer’s journey on your website is vital to increasing conversions and having the best outcome for your business. When it comes to website analytics, the Funnels feature is the best place to start measuring each touch point in the customer journey. From here you’ll find out where you lose your visitors so you can make changes to your website and convert more in the future.

    The funnels feature lets you measure the steps (actions, events and pages) your users go through to reach the desired outcomes you want them to achieve. This gives you valuable insights into the desired journey for your customers. 

    When creating a funnel with the funnels feature, you anticipate the customer journey that you want to measure, for example : 

    Step 1 – Visitor lands on your homepage and sees the promotion you’re offering. 
    Step 2 – They click the call-to-action (CTA) button which leads them to information on the product
    Step 3 – They add the product to their cart
    Step 4 – They fill in their personal information and credit card details
    Step 5 – They click the “pay now” button

    From here you can see exactly how many visitors you lose between each step. Then you can implement new techniques to decrease these drop-offs and evaluate the success of your changes over time.

    But what about the non-conventional routes to conversion ?

    That’s right, visitors can end up in all different directions on your website. It’s important to use other features in Matomo to discover these popular pathways your visitors may be taking before the point of conversion.

    Here are 4 Matomo features for discovering important alternative funnels on your website :

    The transitions feature lets you visualise mini funnels on selected pages. You can see how visitors landed on a specific page, and then where they moved on to from this specific page.

    First you need to identify the page(s) that sells your product or service the most. 

    Whether it’s your homepage, a product page or an information page on your services. The transitions feature will then show you the before and after pathways visitors are already taking to get from page to page

    The transitions feature is located under Behaviour – Pages. Find the important page you would like to analyse and click on the Transitions icon.

    In the example above, you’ll see 18% of visitors who entered from internal pages came from the homepage, which you may have already suspected as the first step in your conversion funnel.

    However, the exact same % of visitors are also entering through a blog post article called /best-of-the-best/

    In this case, it highlights the importance of creating funnels with popular blog posts as the first step in the funnel. Your visitors may have found this post through social media, a search engine etc. Whatever the case, your blog posts could be your biggest influencer for conversions on your website.

    >> Learn more about Transitions

    The overlay feature lets you see exactly where visitors are clicking on your landing pages which moves them either in the right or wrong direction in the conversion funnel. 

    If you see a high percentage of clicks to a page that’s off the beaten track from your desired conversion funnel, use the Funnels feature to follow this pathway and analyse how they get back to the pathway you initially intended them to take.

    The best thing about the page overlay feature is the visualisation showing the results on the landing page itself. This gives you an idea of where they may be getting distracted by the wrong content.

    You can locate the page overlay feature beside the transitions feature, shown in the screenshot below.

    The page overlay feature also gives you a summary of the pageviews, clicks, bounce rates, exit rates and average time spent on page, so you can measure the overall success of each page in the display menu.

    >> Learn more about Page Overlay

    If you’re looking to see many of the most popular pathways your visitors are taking all at once, then Users Flow is a powerful feature which shows this visualisation.

    Note : For Matomo On-Premise users, Users Flow is a premium feature. More information here.

    The thicker the blue line between interactions means the more popular the pathway is. 

    Here you can see how visitors are navigating their way through your website before converting, this presenting clear steps in the conversion funnel that require monitoring and improving on to ensure your efforts are going into the right areas on your website.

    >> Learn more about Users Flow

    Another important feature to use which is integrated within the funnels feature, is row evolution which shows you important changes in your user’s behaviour over time.

    Having row evolution integrated within the funnels feature gives you a big advantage as it lets you measure the specific metrics and landing pages within your conversion funnel.

    You’ll be able to see the increases and decreases in entries and exits to your landing page, as well as increases and decreases in the number of visitors who proceed to the next step in the funnel, and the conversion rate %.

    You’ll also be able to add annotations so you can note all the changes you make to your landing pages over time and quickly identify how these changes impacted your conversion funnels.

    >>Learn more about Row Evolution

    Continually create more and more funnels !

    Measuring the success of the desired pathway you want your customers to take is crucial to ensure you are presenting the best possible user experience for your visitors.

    However, creating funnels for the less desired pathways is equally important. This way you’ll discover popular journeys your visitors are taking within your website you weren’t previously aware of, and can monitor them to make sure they still work in the future. You’ll be able to fix pain points easier and find faster ways to get visitors back on the right track to converting.