101

I include myscript.js in the file http://site1.com/index.html like this:

<script src=http://site2.com/myscript.js></script>

Inside "myscript.js", I want to get access to the URL "http://site2.com/myscript.js". I'd like to have something like this:

function getScriptURL() {
    // something here
    return s
}

alert(getScriptURL());

Which would alert "http://site2.com/myscript.js" if called from the index.html mentioned above.

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
MikeC8
  • 3,783
  • 4
  • 27
  • 33
  • possible duplicate of [What is my script src URL?](http://stackoverflow.com/questions/984510/what-is-my-script-src-url) – ripper234 Dec 25 '12 at 13:54
  • possible duplicate of [How might I get the script filename from within that script?](http://stackoverflow.com/questions/710957/how-might-i-get-the-script-filename-from-within-that-script) – Bergi Jul 17 '13 at 15:42
  • Based on your example URLs, you may want to note what behavior you're expecting if the browser is set to block third party scripts. –  Jun 13 '18 at 19:37
  • To Exact Answer: https://stackoverflow.com/questions/2976651/javascript-how-do-i-get-the-url-of-script-being-called/67235905#67235905 – Airy Apr 23 '21 at 19:35

10 Answers10

62

Everything except IE supports

document.currentScript

Eg

document.currentScript.src
dave1010
  • 15,135
  • 7
  • 67
  • 64
  • 2
    More info: https://developer.mozilla.org/en-US/docs/Web/API/Document/currentScript – Marc Climent Nov 20 '19 at 14:48
  • 2
    More precisely: `document.currentScript.src`. – Basj Dec 21 '20 at 14:31
  • 3
    A word of caution! it will not work if the loaded is script type is module. for more https://stackoverflow.com/questions/2976651/javascript-how-do-i-get-the-url-of-script-being-called/67235905#67235905 – Airy Apr 23 '21 at 19:30
61

From http://feather.elektrum.org/book/src.html:

var scripts = document.getElementsByTagName('script');
var index = scripts.length - 1;
var myScript = scripts[index];

The variable myScript now has the script dom element. You can get the src url by using myScript.src.

Note that this needs to execute as part of the initial evaluation of the script. If you want to not pollute the Javascript namespace you can do something like:

var getScriptURL = (function() {
    var scripts = document.getElementsByTagName('script');
    var index = scripts.length - 1;
    var myScript = scripts[index];
    return function() { return myScript.src; };
})();
lambacck
  • 9,768
  • 3
  • 34
  • 46
  • 29
    Will this always return the URL of the right script though, in all browsers? This looks like it will return the last script tag, but what if the document has more than one script tag in it? – MikeC8 Jun 04 '10 at 18:24
  • The code needs to run in the global context of the script and then you need to cache the value somewhere if you need it later on in the script. If you are using the module pattern to do information hiding, your getScriptURL function could be defined in each script. – lambacck Jun 04 '10 at 18:31
  • 3
    Ok...my question then becomes, do all browsers always fully load an execute the complete contents of a remote script before moving on to the next script tag? How rigorously is this standardized? I could imagine it happening in parallel... – MikeC8 Jun 04 '10 at 18:33
  • 1
    It is required that scripts run completely and in order because of what would happen if the script tag contained a document.write. This is the reason for the recommendations to put scripts at the bottom of the page because they will actually block other content from loading. That said, HTML5 modifies that with the use of the async and defer attributes: http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#script – lambacck Jun 04 '10 at 18:36
  • Further to the scripts at bottom, here is the Yahoo! best practices on that: http://developer.yahoo.com/performance/rules.html#js_bottom – lambacck Jun 04 '10 at 18:40
  • @lambacck: it might be worth noting that `myScript.src` returns full http path of the script only if a full http path is written in `src`. Otherwise on IE6 and IE7 a relative path is returned. On all other browsers including IE8 a full http path is always returned, even if in code it's written a relative path. If interested in more details see here: http://stackoverflow.com/a/3865126/260080 – Marco Demaio Sep 11 '12 at 13:49
  • 9
    This doesn't work if you load the script after the page has loaded using something like this: `document.getElementsByTagName("head")[0].appendChild(scriptElement);` – Seanonymous Feb 27 '13 at 01:35
  • @Seanonymous It probably would if you appended it to the body instead. – lambacck Feb 27 '13 at 21:34
  • 18
    I have come across a case where this algorithm doesn't work reliably. Other script tags that are set to async can run between your script being requested and run. These scripts can add other scripts to the DOM which appear after yours. When your script run the last script on the page is no longer yours and the wrong `src` is returned. – Karl Oct 09 '13 at 12:39
  • @Karl is the script you are trying to run this on also async or just the other scripts? – lambacck Oct 09 '13 at 14:10
  • @lambacck Just the other script is running async. Mine is still synchronous. – Karl Oct 09 '13 at 14:11
  • Does not work with non script tag scripts. What if i'm using require.js? – catbadger Jul 07 '16 at 15:38
  • 1
    https://stackoverflow.com/questions/403967/how-may-i-reference-the-script-tag-that-loaded-the-currently-executing-script Btw this url works even when imported from html imports. Your way does not work with that. Maybe update the comment to point at a much better way? – dtracers Jul 04 '17 at 00:41
  • This does not work for me in Firefox. But the method by pery mimon works. – besimple Mar 22 '18 at 10:13
  • program should be agnostic enough to have correct result of all scenarios. you cannot assume that your script is in the head section and it is the last script in the list. – Sam Saarian Sep 14 '18 at 19:29
  • Doesn't work if the script is loaded with `defer` and there's also INLINE scripts on the page, like `` – Alex from Jitbit Jan 04 '19 at 18:59
  • Note that .src can return an absolute path, even if a relative path was specified. You can use .getAttribute('src') – Илья Зеленько Jun 10 '20 at 08:43
  • Can confirm this does *NOT* work 100% reliably even if your own script is not marked as `async` or `defer`. Sometimes it will return the source of a different script. – Zout Apr 28 '22 at 18:36
61

You can add id attribute to your script tag (even if it is inside a head tag):

<script id="myscripttag" src="http://site2.com/myscript.js"></script>

and then access to its src as follows:

document.getElementById("myscripttag").src

of course id value should be the same for every document that includes your script, but I don't think it is a big inconvenience for you.

tsds
  • 8,700
  • 12
  • 62
  • 83
  • 1
    This answer should be marked as "accepted" as it covers the cases when you call the method not in the "global" script context or in "async" script, and it doesn't depend on the browser implementation. – Sergei Kovalenko Dec 02 '19 at 10:49
  • Note that `.src` can return an absolute path, even if a relative path was specified. You can use `.getAttribute('src')` – Илья Зеленько Jun 10 '20 at 08:42
26

Simple and straightforward solution that work very well :

If it not IE you can use document.currentScript
For IE you can do document.querySelector('script[src*="myscript.js"]')
so :

function getScriptURL(){
 var script =  document.currentScript || document.querySelector('script[src*="myscript.js"]')
 return script.src
}
update

In a module script, you can use:

 import.meta.url

as describe in mdn

pery mimon
  • 7,713
  • 6
  • 52
  • 57
20

I wrote a class to find get the path of scripts that works with delayed loading and async script tags.

I had some template files that were relative to my scripts so instead of hard coding them I made created the class to do create the paths automatically. The full source is here on github.

A while ago I had use arguments.callee to try and do something similar but I recently read on the MDN that it is not allowed in strict mode.

function ScriptPath() {
  var scriptPath = '';
  try {
    //Throw an error to generate a stack trace
    throw new Error();
  }
  catch(e) {
    //Split the stack trace into each line
    var stackLines = e.stack.split('\n');
    var callerIndex = 0;
    //Now walk though each line until we find a path reference
    for(var i in stackLines){
      if(!stackLines[i].match(/http[s]?:\/\//)) continue;
      //We skipped all the lines with out an http so we now have a script reference
      //This one is the class constructor, the next is the getScriptPath() call
      //The one after that is the user code requesting the path info (so offset by 2)
      callerIndex = Number(i) + 2;
      break;
    }
    //Now parse the string for each section we want to return
    pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/);
  }

  this.fullPath = function() {
    return pathParts[1];
  };

  this.path = function() {
    return pathParts[2];
  };

  this.file = function() {
    return pathParts[3];
  };

  this.fileNoExt = function() {
    var parts = this.file().split('.');
    parts.length = parts.length != 1 ? parts.length - 1 : 1;
    return parts.join('.');
  };
}
QueueHammer
  • 10,515
  • 12
  • 67
  • 91
  • This is definitely the best answer. Works more reliably since it relies on the stack trace which will always list the correct precedence of executed scripts. – bucabay Aug 20 '15 at 15:33
  • 1
    A bit late to the party here, but I was trying this code snippet and found that the part where it adds 2 to the current index in the for loop "callerIndex = Number(i) + 2;" seems to break be unnecessary and causes it to not work. Simply eliminating the "+ 2" has it working. Is there something I am misinterpreting or some other scenario that that + 2 would be necessary for? – Scott Smith Nov 25 '15 at 20:40
  • 2
    you don't need to throw "Error" this way ( to get it's ".stack" ) it is just an object like others: console.log( new Error().stack ); – Abdullah Feb 03 '16 at 16:51
  • 1
    Thanks for this idea, and thanks to @AbdullahAydın for the idea of preventing a throw. Then I guess the following one-liner would do the trick, wouldn't it? var scriptUrl = new Error().stack.match(/@(https?:\/\/.+):\d+:\d+/)[1] – Pierre-Antoine Apr 06 '16 at 22:31
  • 1
    Also @Pierre-Antoine keep in mind that Error.prototype.stack property is non-standard :/ you should use it with care. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack#Quick_Links – Abdullah Apr 09 '16 at 10:30
  • 3
    @AbdullahAydın: Note that the stack property of a new error is *not* populated in the IE and Edge browsers until the error is thrown. – Bob Arlof Aug 03 '16 at 14:24
  • 1
    Also note that IE9 (if you care about it) does not have the stack property at all, even when the error is thrown. – dave1010 Aug 23 '16 at 16:27
15

if you have a chance to use jQuery, the code would look like this:

$('script[src$="/myscript.js"]').attr('src');
Mr. Pumpkin
  • 6,212
  • 6
  • 44
  • 60
  • Does it work with defer, async and lazy loading scripts? – Stephan Mar 24 '16 at 15:41
  • It's just looking through the DOM for a script tag with the src "/myscript.js". other attributes won't matter – Rebs Apr 13 '16 at 05:49
  • 1
    To use this with wordpress to in any other place that appends the version you should use $('script[src*="/myscript.js"]').attr('src'); this way it will ignore the ?ver=2.3.3 at the end of the script. The * will keep it working regardless of what is at the end. – Mav2287 Dec 02 '18 at 18:35
2

Following code lets you find the script element with given name

var scripts = document.getElementsByTagName( 'script' );
        var len = scripts.length
        for(var i =0; i < len; i++) {
            if(scripts[i].src.search("<your JS file name") > 0 && scripts[i].src.lastIndexOf("/") >= 0) {
                absoluteAddr = scripts[i].src.substring(0, scripts[i].src.lastIndexOf("/") + 1);
                break;
            }
        }
Varun Bhatia
  • 4,326
  • 32
  • 46
  • It seems that using querySelector() would be a bit shorter and probably quicker nowadays. – Pjotr Sep 13 '21 at 21:26
1
document.currentScript.src

will return the URL of the current Script URL.

Note: If you have loaded the script with type Module then use

import.meta.url

for more import.meta & currentScript.src

Airy
  • 5,484
  • 7
  • 53
  • 78
0

Some necromancy, but here's a function that tries a few methods

function getScriptPath (hint) {
    if (  typeof document === "object" && 
          typeof document.currentScript === 'object' && 
          document.currentScript && // null detect
          typeof document.currentScript.src==='string' && 
          document.currentScript.src.length > 0) {
        return document.currentScript.src;
    }
    
    
    let here = new Error();
    if (!here.stack) {
        try { throw here;} catch (e) {here=e;}
    }
    if (here.stack) {
        
        const stacklines = here.stack.split('\n');
        console.log("parsing:",stacklines);
        let result,ok=false;
        stacklines.some(function(line){
            if (ok) {
               const httpSplit=line.split(':/');
               const linetext = httpSplit.length===1?line.split(':')[0]:httpSplit[0]+':/'+( httpSplit.slice(1).join(':/').split(':')[0]);
               const chop = linetext.split('at ');
               if (chop.length>1) {
                   result = chop[1];
                   if ( result[0]!=='<') {
                      console.log("selected script from stack line:",line);               
                      return true;
                   }
                   result=undefined;
               }
               return false; 
            }
            ok = line.indexOf("getScriptPath")>0;
            return false;
        });
        return result;
    }
    
    if ( hint && typeof document === "object") {
       const script = document.querySelector('script[src="'+hint+'"]');
       return script && script.src && script.src.length && script.src;
    }
    
}
   
   console.log("this script is at:",getScriptPath ())
unsynchronized
  • 4,828
  • 2
  • 31
  • 43
-6

Can't you use location.href or location.host and then append the script name?

Paul
  • 2,729
  • 20
  • 26
  • 2
    That won't work, because the script is running within the http://site1.com/index.html page. So, even through the script is loaded from site2.com, if you access location from within the script, it will return "http://site1.com/index.html"... – MikeC8 Jun 04 '10 at 18:20
  • Previous comment might not make it clear enough, but location.href is the URL of current page. The script will probably be located in some sub-directory like /scripts/script.js or could even be an external one. If there is a need to get the URL of the current script, then there is generally a serious reason for that and it really and simple page URL will not be of any help. – Pjotr Sep 13 '21 at 21:37