experiment_id: web-retrieval-v1
fixture_id: /demos/website-visitors
mode: provenance
representation: html
origin_response_id: 4418fdd61c460efd05f5a42ae2abff04
version: 2026-10-21
version_created_at_utc: 2026-10-21T20:42:35.591Z
version_nonce: 9a9167da3576da8e90b0c2321f650048
generated_at_utc: 2026-11-15T01:34:58.241Z
response_nonce: 7a831c2e57fcdc82c00b07838cb7651e

Website Visitors

48 of 125
This sample website visitor dashboard is created from a simple grid with basic features like sorting, filtering and custom columns.
Result Full HTML CSS JS
Edit Download
Avatar N/A [[index.user.0.name]]

Full Code

<!DOCTYPE html>
<html class="zg-html">

<head>
  <meta charset="utf-8">
  <title>ZingGrid: Blank Grid</title>
  <script nonce="undefined" src="https://cdn.zinggrid.com/zinggrid.min.js"></script>
  <style>
    .zg-body {
      padding: 20px;
      background: #ffffff;
      font-family: 'Work Sans', sans-serif;
    }

    zing-grid {
      max-width: 700px;
      margin: 0 auto;
      font-family: 'Work Sans', sans-serif;
      border: none;
      font-size: 11px;
      color: #212121;
      opacity: 1;
    }

    zing-grid.loading {
      opacity: 0;
      transition: opacity .3s ease-out;
    }

    zing-grid.loading * {
      opacity: 0;
    }

    zg-caption {
      background: #ffffff;
      color: #222222;
      padding: 0px 15px;
      font-size: 18px;
    }

    zg-head {
      letter-spacing: .5px;
    }


    zg-head,
    zg-head-cell {
      font-size: 10px;
      align-items: middle;
      color: #888888;
    }

    zg-cell {
      margin-right: 0px;
    }

    zg-head-cell:first-child,
    zg-cell:first-child {
      border-left: 0px solid white;
    }

    zg-head-cell zg-button,
    zg-head-cell>zg-icon {
      padding-top: 5px;
    }

    zg-icon {
      max-width: 14px;
    }

    zg-row,
    zg-cell {
      padding: 0 10px;
      height: 35px !important;
    }

    zg-cell:nth-child(1) img {
      vertical-align: middle;
    }

    zg-cell:nth-child(1) span {
      vertical-align: middle;
    }

    .zg-body .user--avatar {
      width: 20px;
      margin-right: 7px;
    }

    .zg-body .recent {
      color: #69B668;
    }

    .zg-body .unknown {
      color: #ACAAAE;
    }

    zg-filter input {
      margin-left: 7px;
    }

    zing-grid[loading] {
      height: 604px;
    }
  </style>
</head>

<body class="zg-body">

  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
  <link href="https://fonts.googleapis.com/css?family=Work+Sans:400,600" rel="stylesheet">

  <zing-grid src="https://zinggrid-marketing.firebaseio.com/website-visitors-milliseconds" pager sort filter filter-on="rendered" gridlines="both" page-size="10" page-size-options="5,10,20" class="loading" layout="row" layout-controls="disabled">
    <zg-colgroup>
      <zg-column frozen index="user" header="<i class='fas fa-users'></i> Name">
        <img src="[[index.user.0.avatar]]" alt="Avatar N/A" class="user--avatar" />
        <span>[[index.user.0.name]]</span>
      </zg-column>
      <zg-column index="lastSeen" type="number" renderer="renderLastSeen" header="<i class='far fa-calendar-alt'></i> Last Seen"></zg-column>
      <zg-column index="firstSeen" type="number" renderer="renderLastSeen" header="<i class='far fa-calendar-alt'></i> First Seen"></zg-column>
      <zg-column index="signedUp" type="number" renderer="renderLastSeen" header="<i class='far fa-calendar-alt'></i> Signed Up"></zg-column>
      <zg-column index="webSessions" type="number" header="<i class='fas fa-chart-line'></i> Web Sessions"></zg-column>
      <zg-column index="city" header="<i class='fas fa-city'></i> City"></zg-column>
    </zg-colgroup>
  </zing-grid>

  <script>
    ZingGrid.setLicense(['26ccbfec16b8be9ee98c7d57bee6e498']);
    var MINUTE = 1000 * 60;
    var HOUR = 1000 * 60 * 60;
    var DAY = 1000 * 60 * 60 * 24;
    var WEEK = DAY * 7;
    var MONTH = DAY * 30;

    function renderLastSeen(value) {
      if (value >= MONTH) {
        return `${parseInt(value / MONTH)} months ago`;
      } else if (value >= WEEK) {
        return `${parseInt(value / WEEK)} weeks ago`;
      } else if (value >= DAY) {
        return `${parseInt(value / DAY)} days ago`;
      } else if (value >= HOUR) {
        return `${parseInt(value / HOUR)} hours ago`;
      } else if (value >= MINUTE) {
        return `${parseInt(value / MINUTE)} minutes ago`;
      } else if (value < MINUTE) {
        return `Just now`;
      }
    }
    // Custom loading class for CSS handling
    const zgLoaded = document.querySelector('zing-grid');
    zgLoaded.addEventListener('grid:ready', () => {
      setTimeout(() => zgLoaded.classList.remove('loading'), 0);
    });
  </script>
</body>

</html>
<!DOCTYPE html>
<html class="zg-html">
  <head>
    <meta charset="utf-8">
    <title>ZingGrid: Blank Grid</title>
    <script src="https://cdn.zinggrid.com/zinggrid.min.js"></script>
  </head>
  <body class="zg-body">
    
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
  	<link href="https://fonts.googleapis.com/css?family=Work+Sans:400,600" rel="stylesheet">

    <zing-grid 
      src="https://zinggrid-marketing.firebaseio.com/website-visitors-milliseconds"
      pager
      sort
      filter
      filter-on="rendered"
      gridlines="both"
      page-size="10"
      page-size-options="5,10,20"
      class="loading"
      layout="row" layout-controls="disabled"
    >
      <zg-colgroup>
        <zg-column frozen index="user" header="<i class='fas fa-users'></i> Name">
          <img src="[[index.user.0.avatar]]" alt="Avatar N/A" class="user--avatar"/>
          <span>[[index.user.0.name]]</span>
        </zg-column>
        <zg-column index="lastSeen" type="number" renderer="renderLastSeen" header="<i class='far fa-calendar-alt'></i> Last Seen"></zg-column>
        <zg-column index="firstSeen" type="number" renderer="renderLastSeen" header="<i class='far fa-calendar-alt'></i> First Seen"></zg-column>
        <zg-column index="signedUp" type="number" renderer="renderLastSeen" header="<i class='far fa-calendar-alt'></i> Signed Up"></zg-column>
        <zg-column index="webSessions" type="number" header="<i class='fas fa-chart-line'></i> Web Sessions"></zg-column>
        <zg-column index="city" header="<i class='fas fa-city'></i> City"></zg-column>
      </zg-colgroup>
    </zing-grid>
    
  </body>
</html>
.zg-body {
  padding: 20px;
	background:#ffffff;
	font-family: 'Work Sans', sans-serif;
}

zing-grid {
  max-width: 700px;
  margin: 0 auto;
	font-family: 'Work Sans', sans-serif;
  border: none;
  font-size: 11px;
  color: #212121;
  opacity: 1;
}
zing-grid.loading { opacity:0; transition:opacity .3s ease-out; }
zing-grid.loading * { opacity:0; }

zg-caption {
 	background: #ffffff;
  color: #222222;
  padding: 0px 15px;
  font-size: 18px;
}

zg-head {
	letter-spacing: .5px;
}


zg-head, zg-head-cell {
	font-size: 10px;
  align-items: middle;
  color: #888888;
}

zg-cell {
  margin-right: 0px;
}

zg-head-cell:first-child,
zg-cell:first-child {
  border-left: 0px solid white;
}

zg-head-cell zg-button,
zg-head-cell > zg-icon {
  padding-top: 5px;
}

zg-icon {
 	max-width: 14px; 
}

zg-row, zg-cell {
  padding: 0 10px; 
  height: 35px !important;
}

zg-cell:nth-child(1) img {
	vertical-align: middle;
}

zg-cell:nth-child(1) span {
	vertical-align: middle;
}

.zg-body .user--avatar { 
  width: 20px; 
  margin-right: 7px;
}

.zg-body .recent {
  color: #69B668;
}

.zg-body .unknown {
  color: #ACAAAE;
}

zg-filter input {
  margin-left: 7px;
}
var MINUTE = 1000 * 60;
var HOUR = 1000 * 60 * 60;
var DAY = 1000 * 60 * 60 * 24;
var WEEK = DAY * 7;
var MONTH = DAY * 30;

function renderLastSeen(value) {
  if (value >= MONTH) {
    return `${parseInt(value / MONTH)} months ago`;
  } else if (value >= WEEK) {
    return `${parseInt(value / WEEK)} weeks ago`;
  } else if (value >= DAY) {
    return `${parseInt(value / DAY)} days ago`;
  } else if (value >= HOUR) {
    return `${parseInt(value / HOUR)} hours ago`;
  } else if (value >= MINUTE) {
    return `${parseInt(value / MINUTE)} minutes ago`;
  } else if (value < MINUTE) {
    return `Just now`;
  }
}
// Custom loading class for CSS handling
const zgLoaded = document.querySelector('zing-grid');
zgLoaded.addEventListener('grid:ready', () => {
  setTimeout(() => zgLoaded.classList.remove('loading'), 0);
});

Interested in this demo? Modify it to your needs in ZingSoft Studio, our testing sandbox. It's free to sign up, and you can come back and edit at any time!

Edit in Studio

Demo Gallery