Is there any API service that converts a CSV file (inside url) to a simple table on a webpage so I can call an API to take a screenshot of this page?

I have a URL that when I open, downloads a CSV file to my computer.

But instead of downloading it to my computer, I would like a service where I would put the URL and it would convert this file to a page with the online table.

Because from this online table I’m going to use an API ( to take a screenshot of the page, which in this case would be a screenshot of the table containing all the data in this CSV file.

Does this service exist?

Note: The option to use Google App Script to convert the CSV into a table and publish this table as a page does not solve my problem, because the page created i need to scroll the screen manually for the new data to appear, so when the API takes the screenshot , only a part of the table appears.

unable to access webpage on IOS devices

I am currently developing an IOT device that can connect to the internet but works offline as well.

I have designed it so that when the user first connects to the wifi network, a browser window automaticly opens that displays the folowing html:

<!DOCTYPE html><html><head></head><body>
   <p><a href='http://samplepage.local:8000'>click here if the portal doesnt load</a></p>

The purpose of this website is only to automaticly redirect the user to the ACTUAL webpage, which is http://samplepage.local:8000 (on port 8000). Idealy the user will never see this page except maybe for a split second, and if it gets stuck on it for some reason, he can just press the url to redirect to the page.

This works flawlessly on both android and windows, regardless of browser. However, on IOS (any iphone i have tried from 5S to 11) it only shows the initial capture page shown above, where even clicking the url doesnt work. If i then go to safari and manualy enter http://samplepage.local:8000 ,it doesnt want to connect to it as well.

for some extra info, the device which i am connecting to (ESP32 microcontroler), serves also as a DNS server and a wifi station and access point.
the network setings, as shown on the ipohne are the folowing:
ip adress:

this is when the device is not connected to the internet. when it is connected to the internet it leases out a more normal IP adress like

Would this be an iphone or a safari problem? does the iphone have any logs i can check for clues?
Does ios have some extra security limitations that prevent these kinds of pages being loaded?

javascript – Is there a way to obtain the webpage height to adapt the iframe size?

After visiting a lot Stackoverflow for the past years, I am now decided to ask a question.

I am using Mailchimp to send newsletters, and WordPress to publish articles and e-commerce. I found a way, using Zapier or, to publish new newsletters to the website and feature them seamlessly.

But I had to define the webpage height of the iframe. However, this height changes from one newsletter to another.

The process is the following :

The newsletters is published on Mailchimp > The campaign URL is then added to a pre-configured iframe script > The whole is published in a new article on WordPress.

I read a lot about iframe javascripts or jquery, but I am obviously not able to add content or scripts in a Mailchimp archive page.

I am able to add a Javascript or Python code between the steps to output the page height, can this be a solution, and how can I manage to do this ? Also, can I had a script to the WordPress pages to calculate and populate the iframed page height ?


ios – Why could some webpage works on wifi and not on cellular data?

One script of a webpage is failing in iOS. I thought it was related to the new “prevent cross-site tracking” setting, but it’s because of the network used!

It works in a wifi network, but it doesn’t if using mobile/cellular data. I can’t imagine or find why, so I’m looking for some idea between you, the Apple experts.

php – How to add a element to a webpage that keeps refreshing with a updated price

$url = "";
$price = json_decode(file_get_contents($url), true);
echo "$".$btcPrice=number_format($price('bpi')('USD')('rate_float'),2);

The above code when I add it to my page it shows me the current price. I am wondering what is the correct way to add code to a site that will update the price every minute without refreshing the entire page.

I just need a pointer to what method to use or even what search term to use to find information about this. I tries searches for words like price stream, live update element, timer, etc but nothing that gave me the answer to how to implement this.


beginner – Find and replace text in a webpage with JavaScript

I am new to web development and would like to get feedback on a JavaScript library that automatically finds and replaces text on a webpage using the MutationObserver interface. The code below is quite long so I’ll try to explain briefly what happens when you create a TextObserver object:

  1. Use a TreeWalker object to replace every Text node
  2. Iterate through each watched attribute and select matching elements, replacing their attributes
  3. Use another TreeWalker to find elements with nonempty CSS content property values and override them by injecting a stylesheet with the replaced values
  4. Find open Shadow DOMs and recursively apply the above steps to them
  5. Set up a MutationObserver to automatically do replacements on added or modified nodes

The README may also be helpful in understanding how it is meant to be used. At over 300 lines I understand I’ll probably receive higher-level reviews than in-depth, line-by-line examination. So I’ll ask accordingly:

  • As you might have inferred from the heavy use of private variables, I have a Java background. Is such usage of OOP/encapsulation idiomatic in JS?
  • To prevent replacements made by one observer’s callback from alerting other observers and creating an infinite “ping-pong” effect, I store every created TextObserver in a static class variable and deactivate them before running the callback. Is this good practice? It feels like a God object.
  • Is there anything else I should do to make this more fit for use as a library? (UMD?) And is the README understandable? (If it is appropriate to ask for reviews on documentation here.)
class TextObserver {
    #targets = new Set();
    #processed = new Set();
    #connected = true;

    // Keep track of all created observers to prevent infinite callbacks
    static #observers = new Set();

    // Use static read-only properties as class constants
    static get #IGNORED_NODES() {
        // Node types that implement the CharacterData interface but are not relevant or visible to the user
    static get #IGNORED_TAGS() {
        // Text nodes that are not front-facing content
        return ('SCRIPT', 'STYLE', 'NOSCRIPT');
    static get #WATCHED_ATTRIBUTES() {
        // HTML attributes that get rendered as visible text
        return {
            'placeholder': ('input', 'textarea'),
            'alt': ('img', 'area', 'input(type="image")', '(role="img")'),
            'value': ('input(type="button")'),
            'title': ('*'),
    static get #WATCHED_CSS() {
        // CSS pseudo-elements that can have the content property set
        return ('::before', '::after', '::marker');
    static get #CONFIG() {
        return {
            subtree: true,
            childList: true,
            characterData: true,
            attributeFilter: Object.keys(TextObserver.#WATCHED_ATTRIBUTES),

    // Override attachShadow to always force open mode so we can look inside them
    static #staticConstructor = (() => {
        Element.prototype._attachShadow = Element.prototype.attachShadow;
        Element.prototype.attachShadow = function() {
            let shadowRoot = this._attachShadow({ mode: 'open' });
            // Find observers whose target includes the shadow
            let observers = ();
            for (const textObserver of TextObserver.#observers) {
                let found = false;
                for (const target of textObserver.#targets) {
                    if (target.contains( {
                        found = true;
                if (textObserver.#performanceOptions.shadows && found) {
            observers.forEach(observer => observer.observe(shadowRoot, TextObserver.#CONFIG));
            return shadowRoot;

    constructor(callback, target = document, processExisting = true, performanceOptions = {
        contentEditable: true,
        attributes: true,
        shadows: true,
        iconFonts: false,
        cssContent: false,
    }) {
        this.#callback = callback;
        this.#performanceOptions = performanceOptions;

        // If target is entire document, manually process <title> and skip the rest of the <head>
        // Processing the <head> can increase runtime by a factor of two
        if (target === document) {
            document.title = callback(document.title);
            // Sometimes <body> may be missing, like when viewing an .SVG file in the browser
            if (document.body !== null) {
                target = document.body;
            } else {
                console.warn('Document body does not exist, exiting...');


        if (processExisting) {
            TextObserver.#flushAndSleepDuring(() => this.#targets.forEach(target => this.#processNodes(target)));

        const observer = new MutationObserver(mutations => {
            const records = ();
            for (const textObserver of TextObserver.#observers) {
                // This ternary is why this section does not use flushAndSleepDuring
                // It allows the nice-to-have property of callbacks being processed in the order they were declared
                records.push(textObserver === this ? mutations : textObserver.#observer.takeRecords());
            let i = 0;
            for (const textObserver of TextObserver.#observers) {

            TextObserver.#observers.forEach(textObserver => textObserver.#targets.forEach(
                target => textObserver.#observer.observe(target, TextObserver.#CONFIG)
        this.#targets.forEach(target => observer.observe(target, TextObserver.#CONFIG));

        this.#observer = observer;

    disconnect(flush = true) {
        if (!this.#connected) {
            console.warn('This TextObserver instance is already disconnected!');
        this.#connected = false;
        if (flush) {
            TextObserver.#flushAndSleepDuring(() => {});

    reconnect(reprocess = true) {
        if (this.#connected) {
            console.warn('This TextObserver instance is already connected!');
        this.#connected = true;
        if (reprocess) {
            TextObserver.#flushAndSleepDuring(() => this.#targets.forEach(target => {
        this.#targets.forEach(target => this.#observer.observe(target, TextObserver.#CONFIG));

    #observerCallback(mutations) {
        // Sometimes, MutationRecords of type 'childList' have added nodes with overlapping subtrees
        // This can cause resource usage to explode with "recursive" replacements, e.g. expands -> physically expands
        // The processed set ensures that each added node is only processed once so the above doesn't happen
        // We must save attribute mutations and process them at the end because adding them to processed would limit
        // elements to one processed attribute per callback
        const attributeMutations = ();
        for (const mutation of mutations) {
            const target =;
            switch (mutation.type) {
                case 'childList':
                    for (const node of mutation.addedNodes) {
                        if (node.nodeType === Node.TEXT_NODE) {
                            if (this.#valid(node) && !this.#processed.has(node)) {
                                node.nodeValue = this.#callback(node.nodeValue);
                        } else if (!TextObserver.#IGNORED_NODES.includes(node.nodeType)) {
                            // If added node is not text, process subtree
                case 'characterData':
                    if (this.#valid(target) && !this.#processed.has(target)) {
                        target.nodeValue = this.#callback(target.nodeValue);
                case 'attributes':
                    if (this.#performanceOptions.attributes && !this.#processed.has(target)) {
        for (const attributeMutation of attributeMutations) {
            // Find if element with changed attribute matches a valid selector
            const target =;
            const attribute = attributeMutation.attributeName;
            const selectors = TextObserver.#WATCHED_ATTRIBUTES(attribute);
            let matched = false;
            for (const selector of selectors) {
                if (target.matches(selector)) {
                    matched = true;
            const value = target.getAttribute(attribute);
            if (matched && value) {
                target.setAttribute(attribute, this.#callback(value));

    static #flushAndSleepDuring(callback) {
        // Disconnect all other observers to prevent infinite callbacks
        const records = ();
        for (const textObserver of TextObserver.#observers) {
            // Collect pending mutation notifications
        // This is in its own separate loop from the above because we want to disconnect everything before proceeding
        // Otherwise, the mutations in the callback may trigger the other observers
        let i = 0;
        for (const textObserver of TextObserver.#observers) {
        TextObserver.#observers.forEach(textObserver => textObserver.#targets.forEach(
            target => textObserver.#observer.observe(target, TextObserver.#CONFIG)

    #valid(node) {
        return (
            // Sometimes the node is removed from the document before we can process it, so check for valid parent
            node.parentNode !== null
            && !TextObserver.#IGNORED_NODES.includes(node.nodeType)
            && !TextObserver.#IGNORED_TAGS.includes(node.parentNode.tagName)
            // Ignore contentEditable elements as touching them messes up the cursor position
            && (!this.#performanceOptions.contentEditable || !node.parentNode.isContentEditable)
            // HACK: workaround to avoid breaking icon fonts
            && (!this.#performanceOptions.iconFonts || !window.getComputedStyle(node.parentNode).getPropertyValue('font-family').toUpperCase().includes('ICON'))

    #processNodes(root) {
        // Process valid Text nodes
        const nodes = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, { acceptNode: node => (
            this.#valid(node) && !this.#processed.has(node)) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
        while (nodes.nextNode()) {
            nodes.currentNode.nodeValue = this.#callback(nodes.currentNode.nodeValue);
        // Use temporary set since instantly adding would prevent elements from having multiple attributes/CSS processed
        const tempProcessed = new Set();
        if (this.#performanceOptions.attributes) {
            // Process special attributes
            for (const (attribute, selectors) of Object.entries(TextObserver.#WATCHED_ATTRIBUTES)) {
                root.querySelectorAll(selectors.join(', ')).forEach(element => {
                    if (!this.#processed.has(element)) {
                        const value = element.getAttribute(attribute);
                        if (value !== null) {
                            element.setAttribute(attribute, this.#callback(value));
        if (this.#performanceOptions.cssContent) {
            // Process CSS generated text
            const styleElement = document.createElement('style');
            let styles = '';
            let i = 0;
            const elements = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
                acceptNode: node => !this.#processed.has(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
            while (elements.nextNode()) {
                const node = elements.currentNode;
                for (const pseudoClass of TextObserver.#WATCHED_CSS) {
                    const content = window.getComputedStyle(node, pseudoClass).content;
                    if (/^'(^')+'$/.test(content) || /^"(^")+"$/.test(content)) {
                        const newClass = 'TextObserverHelperAssigned' + i;
                        styles += `.${newClass}${pseudoClass} {
                            content: "${this.#callback(content.substring(1, content.length - 1))}" !important;
            styleElement.textContent = styles;
        for (const element of tempProcessed) {
        if (this.#performanceOptions.shadows) {
            // Manually find and process open Shadow DOMs because MutationObserver doesn't pick them up
            const shadowRoots = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
                acceptNode: node => node.shadowRoot ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
            let shadowRoot = shadowRoots.currentNode.shadowRoot;
            // First node may or may not have a shadow root
            if (!shadowRoot) {
                shadowRoot = shadowRoots.nextNode();
            while (shadowRoot) {
                if (!this.#targets.has(shadowRoot)) {
                    if (this.#observer !== undefined) {
                        this.#observer.observe(shadowRoot, TextObserver.#CONFIG);
                shadowRoot = shadowRoots.nextNode();

// A good page to try this out on would be
const badWordFilter = new TextObserver(text => text.replaceAll(/heck/gi, 'h*ck'));

javascript – Randomly place Divs on webpage and make sure they don’t overlap

Currently I am working on a project for which I want to have the different links (div elements) placed randomly on my webpage. To accomplish this, I first generate a set of coordinates and later check wether they overlap (SO thread, user @Robson helped me figure things out).

However, since this is my first JavaScript project that is longer than 15 lines of code, I am am sure to have missed some best-practises or simply took a too compliacted approach. I am happy to learn about my mistakes and how to come up with more efficient or clean code!

Maybe I can describe my thought process a little:

  • getMaxDimension: in Order to have the divs not overflow the site, I need to only spawn them in coordinates far enough away from the right and bottom border of the screen, since coordinates are calculated from the top left corner.
  • getOffset: To check wether two divs overlay, I check if any point of the polygon of div a is inside div b. To do that I calculate all the coordinates and store them in an object.
  • getOverlap: basically just checks if div a’s points and div b’s points are inside of each other. The code seems rather complicated, but is just an implementation of the mathematical notation
  • getChar: (I really think there are better ways to do this); In order to control every div uniquely, they all need different ID’s. However, id=1, id=2 and so on didn’t work (maybe they are not allowed?). Now in order to “convert” iteration variables i and j to the corresponding div I just chose letters.


    <div class="random" id="a">Div1</div>
    <div class="random" id="b">Div2</div>
    <div class="random" id="c">Div3</div>
    <div class="random" id="d">Div4</div>
    <div class="random" id="e">Div5</div>
div {
  width: 60px;
  height: 60px;
  position: absolute;

#a {
  background-color: pink;

#b {
  background-color: lightblue;

#c {
  background-color: lightgreen;

#d {
  background-color: silver;

#e {
  background-color: yellow;
 // Returns largest div's width and height
 function getMaxDimension(arr) {
   var maxWidth = 0;
   for (var i = 0; i < div_selection.length; i++) {
     if (div_selection(i).offsetWidth > maxWidth) {
       maxWidth = div_selection(i).offsetWidth;
   var maxHeight = 0;
   for (var i = 0; i < div_selection.length; i++) {
     if (div_selection(i).offsetHeight > maxHeight) {
       maxHeight = div_selection(i).offsetHeight;
   var values = {
     maxWidth: maxWidth,
     maxHeight: maxHeight
   return values;

 // Retruns a random number x; min < x < max
 function getRandomNumber(min, max) {
   return Math.random() * (max - min) + min;

 // returns the position in xy-space of every corner of a rectangular div
 function getOffset(element) {
   var position_x = element.offsetLeft;
   var position_y = element.offsetTop;
   var height_x = element.offsetWidth;
   var height_y = element.offsetHeight;
   var tolerance = 0; // will get doubled
   return {
     A: {
       y: position_y - tolerance,
       x: position_x - tolerance
     B: {
       y: position_y + height_x + tolerance,
       x: position_x - tolerance
     C: {
       y: position_y + height_x + tolerance,
       x: position_x + height_y + tolerance
     D: {
       y: position_y - tolerance,
       x: position_x + height_y + tolerance

 // Returns true if any corner is inside the coordinates of the other div
 function getOverlap(div1, div2) {
   coor_1 = getOffset(document.getElementById(div1));
   coor_2 = getOffset(document.getElementById(div2));
   return (
     (coor_1.A.x <= coor_2.A.x && coor_2.A.x <= coor_1.D.x) && (coor_1.A.y <= coor_2.A.y && coor_2.A.y <= coor_1.B.y) ||
     (coor_1.A.x <= coor_2.B.x && coor_2.B.x <= coor_1.D.x) && (coor_1.A.y <= coor_2.B.y && coor_2.B.y <= coor_1.B.y) ||
     (coor_1.A.x <= coor_2.C.x && coor_2.C.x <= coor_1.D.x) && (coor_1.A.y <= coor_2.C.y && coor_2.C.y <= coor_1.B.y) ||
     (coor_1.A.x <= coor_2.D.x && coor_2.D.x <= coor_1.D.x) && (coor_1.A.y <= coor_2.D.y && coor_2.D.y <= coor_1.B.y)

 // Number to Letter
 function getChar(n) {
   var ordA = 'a'.charCodeAt(0);
   var ordZ = 'z'.charCodeAt(0);
   var len = ordZ - ordA + 1;

   var s = "";
   while (n >= 0) {
     s = String.fromCharCode(n % len + ordA) + s;
     n = Math.floor(n / len) - 1;
   return s;

 var div_selection = document.getElementsByClassName("random");

 maxDimensions = getMaxDimension(div_selection);
 var widthBoundary = maxDimensions.maxWidth;
 var heightBoundary = maxDimensions.maxHeight;

 for (var i = 0; i < div_selection.length; i++) {
   var isOverlapping = false;
   var attemptCount = 0;
   do {
     randomLeft = getRandomNumber(0, window.innerWidth - widthBoundary);
     randomTop = getRandomNumber(0, window.innerHeight - heightBoundary);
     div_selection(i).style.left = randomLeft + "px";
     div_selection(i) = randomTop + "px";     
     isOverlapping = false;
     for (var j = 0; j < i; j++) {
        if (getOverlap(getChar(i), getChar(j))) {
        isOverlapping = true;
   } while (++attemptCount < 50 && isOverlapping);

 // check every element
 for (var i = 0; i < div_selection.length; i++) {
   for (var j = i + 1; j < div_selection.length; j++) {
     console.log(i, j)
     console.log(getChar(i), getChar(j))
     console.log(getOverlap(getChar(i), getChar(j)))

animation – Optimal Format for Video on Webpage

I am working on a website that demos an app, and am trying to embed a simple preview of the app in the hero banner at the top of the page. Currently I have the preview as an mp4 recording of the app in a simulated iPhone, but that format lacks transparency so there is an ugly white rectangle around the video. I’ve heard that mp4s are not the most efficient format to use on the web, so I’m curious what the optimal format is. Should I try to convert it as a gif, even though the demo wouldn’t look as nice? What formats would accomplish the purpose and load efficiently?

html – Can I somehow extract data from a webpage for analysis?

Apologies if I am asking in the wrong place. Or even if what I’m asking is impossible / stupid. But if you don’t ask, you don’t get as my dear old dad used to say…..I hope you guys are understanding, some of the other Stack pages seem to have quite hostile inhabitants who vote you down even when you’ve complied with everything they ask…..

I play online backgammon – the site I use doesn’t have the functionality to export games so I’d like to try and “snag” all of my game data so that I can push them through some analysis tools to try and improve my game.

There are 9,000+ games so 9,000+ individual webpages.

Is it remotely possible to do what I’d like? I have uploaded a webpage from the site to – the part I’m interested in is the left hand side marked “turns”, so roll 1 was 3-1 and the move was 8/5, 6/5.

Thank you for reading.

website design – Fonts look blurred in different areas of a webpage

I am using a monospace font in the text on my webpage. For larger sizes, the font appears to be normal without any discrepancies; however, in small paragraph-appropriate sizes, the variations in the font become more noticeable to the point where certain characters(the number 1) appear bulged in one end. Notice that this does not occur for all instances of the character; for some instances, there is no discrepancy. I am certain that this is caused due to font spacing and that they are caused when the character ,”lands” in the middle of a pixel.

Notice: I am using Mac OS X with sub-pixel anti-aliasing turned on. This is not causing the issue.

Edit: I am using Meslo LG M as the font.